Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ 기능 추가 : AdminEmailVerificationVO 이메일에 따른 사번 검증 VO 기능 추가 #278

Merged
merged 20 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f4ac8ae
✨ 기능 수정 : 쿠키 만료 시간 변경 기능 수정
sksmsdlskgus Nov 26, 2024
b8def6c
Merge branch 'develop' of https://github.com/LearnsMate/LearnsMateBac…
sksmsdlskgus Nov 27, 2024
cff00b3
✨ 기능 추가 : Admin Setter 기능 추가
sksmsdlskgus Nov 28, 2024
41c9d8f
✨ 기능 추가 : Redis 및 SMTP gradle 기능 추가
sksmsdlskgus Nov 28, 2024
443e249
✨ 기능 추가 : EmailConfig 기능 추가
sksmsdlskgus Nov 28, 2024
2462d41
✨ 기능 추가 : EmailService 기능 추가
sksmsdlskgus Nov 28, 2024
1959743
✨ 기능 추가 : RedisConfig 기능 추가
sksmsdlskgus Nov 28, 2024
1c23eb7
✨ 기능 추가 : ResponseEmailDTO 이메일 인증 DTO 기능 추가
sksmsdlskgus Nov 28, 2024
5509936
✨ 기능 추가 : ResponseEmailMessageVO 이메일 인증 성공 메시지 담는 기능 추가
sksmsdlskgus Nov 28, 2024
8c3c513
✨ 기능 추가 : RequestResetPasswordVO 비밀번호 reset정보 담는 기능 추가
sksmsdlskgus Nov 28, 2024
941d4b9
✨ 기능 추가 : EmailVerificationVO 이메일, 인증코드, 사번 정보 담는 기능 추가
sksmsdlskgus Nov 28, 2024
02abcc9
✨ 기능 추가 : AdminEmailVerificationVO 이메일에 따른 사번 검증 VO 기능 추가
sksmsdlskgus Nov 28, 2024
0f04c7d
✨ 기능 수정 : updateAdmin 직원 정보 수정 Service 기능 수정
sksmsdlskgus Nov 28, 2024
e73a4b7
✨ 기능 추가 : findUserByEmail 이메일로 회원찾기 Service 기능 추가
sksmsdlskgus Nov 28, 2024
8f742bb
✨ 기능 추가 : resetPassword 비밀번호 reset Service 기능 추가
sksmsdlskgus Nov 28, 2024
a5006af
✨ 기능 수정 : updateAdmin 직원 정보 수정 Controller 기능 수정
sksmsdlskgus Nov 28, 2024
a37ebbb
✨ 기능 추가 : sendVerificationEmailPassword 직원 비밀번호 재설정시 이메일 전송 Controlle…
sksmsdlskgus Nov 28, 2024
2262716
✨ 기능 추가 : verifyEmail 비번 재설정 전 이메일 인증번호 검증 Controller 기능 추가
sksmsdlskgus Nov 28, 2024
6cedc3d
✨ 기능 추가 : resetPassword 비밀번호 재설정 Controller 기능 추가
sksmsdlskgus Nov 28, 2024
71d783a
✨ 기능 추가 : logging 기능 추가
sksmsdlskgus Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions LearnsMate/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ dependencies {
// EC2 인스턴스 헬스 체크를 위한 actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'

// Redis 통합
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// Redis 연결 풀 관리
// ( Redis와의 연결을 반복적으로 열고 닫는 대신, 연결을 풀(pool)에 저장해 두고 재사용함으로써 성능을 최적화하고 리소스를 절약 )
implementation 'org.apache.commons:commons-pool2'
// SMTP 이메일 발송
implementation 'org.springframework.boot:spring-boot-starter-mail'

// jwt token을 위한 옵션
// https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package intbyte4.learnsmate.admin.controller;

import intbyte4.learnsmate.admin.domain.dto.AdminDTO;
import intbyte4.learnsmate.admin.domain.dto.ResponseEmailDTO;
import intbyte4.learnsmate.admin.domain.entity.CustomUserDetails;
import intbyte4.learnsmate.admin.domain.vo.request.AdminEmailVerificationVO;
import intbyte4.learnsmate.admin.domain.vo.request.EmailVerificationVO;
import intbyte4.learnsmate.admin.domain.vo.request.RequestEditAdminVO;
import intbyte4.learnsmate.admin.domain.vo.request.RequestResetPasswordVO;
import intbyte4.learnsmate.admin.domain.vo.response.ResponseEditAdminVO;
import intbyte4.learnsmate.admin.domain.vo.response.ResponseEmailMessageVO;
import intbyte4.learnsmate.admin.domain.vo.response.ResponseFindAdminVO;
import intbyte4.learnsmate.admin.mapper.AdminMapper;
import intbyte4.learnsmate.admin.service.AdminService;
import intbyte4.learnsmate.admin.service.EmailService;
import intbyte4.learnsmate.common.exception.CommonException;
import intbyte4.learnsmate.common.exception.StatusEnum;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -15,6 +23,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
Expand All @@ -28,6 +37,7 @@ public class AdminController {

private final AdminService adminService;
private final AdminMapper adminMapper;
private final EmailService emailService;

@Operation(summary = "직원 단건 조회")
@GetMapping("/{adminCode}")
Expand All @@ -37,10 +47,9 @@ public ResponseEntity<ResponseFindAdminVO> getAdmin(@PathVariable Long adminCode
}

@Operation(summary = "직원 정보 수정")
@PatchMapping("/{adminCode}")
public ResponseEntity<ResponseEditAdminVO> updateAdmin(@PathVariable Long adminCode,
@RequestBody RequestEditAdminVO editAdminVO) {
AdminDTO updatedAdmin = adminService.updateAdmin(adminCode, adminMapper.fromVoToDto(editAdminVO));
@PatchMapping("/password")
public ResponseEntity<ResponseEditAdminVO> updateAdmin(@RequestBody RequestEditAdminVO editAdminVO) {
AdminDTO updatedAdmin = adminService.updateAdmin(adminMapper.fromVoToDto(editAdminVO));
return ResponseEntity.status(HttpStatus.OK).body(adminMapper.fromDtoToEditResponseVO(updatedAdmin));
}

Expand Down Expand Up @@ -79,4 +88,63 @@ public ResponseEntity<?> logout(HttpServletResponse response) {
return ResponseEntity.ok().body("로그아웃 성공");
}

// 인증버튼
@Operation(summary = "직원 비밀번호 재설정시 이메일 전송")
@PostMapping("/verification-email/password")
public ResponseEmailDTO<?> sendVerificationEmailPassword(@RequestBody @Validated AdminEmailVerificationVO request) {

log.info("POST /admin/verification-email/password 요청 도착: request={}", request);

// 입력한 사번 코드와 이메일의 정보 검증
AdminDTO adminByEmail = adminService.findUserByEmail(request.getEmail());

if (adminByEmail == null || !adminByEmail.getAdminCode().equals(request.getAdminCode())) {
throw new CommonException(StatusEnum.EMAIL_NOT_FOUND);
}
// 이메일로 인증번호 전송
return getResponseEmailDTO(request);
}

private ResponseEmailDTO<?> getResponseEmailDTO(AdminEmailVerificationVO request) {
// 이메일로 인증번호 전송
try {
emailService.sendVerificationEmail(request.getEmail());

ResponseEmailMessageVO responseEmailMessageVO =new ResponseEmailMessageVO();
responseEmailMessageVO.setMessage("인증 코드가 이메일로 전송되었습니다.");
return ResponseEmailDTO.ok(responseEmailMessageVO);
} catch (Exception e) {
return ResponseEmailDTO.fail(new CommonException(StatusEnum.INTERNAL_SERVER_ERROR));
}
}


// 다음버튼
@Operation(summary = "비번 재설정 전 이메일 인증번호 검증")
@PostMapping("/verification-email/confirmation")
public ResponseEmailDTO<?> verifyEmail(@RequestBody @Validated EmailVerificationVO request) {
log.info("POST /admin/verification-email/confirmation 요청 도착: request={}", request);

boolean isVerified = emailService.verifyCode(request.getEmail(), request.getCode());

ResponseEmailMessageVO responseEmailMessageVO =new ResponseEmailMessageVO();
responseEmailMessageVO.setMessage("이메일 인증이 완료되었습니다.");
if (isVerified) {
return ResponseEmailDTO.ok(responseEmailMessageVO);
} else {
return ResponseEmailDTO.fail(new CommonException(StatusEnum.INVALID_VERIFICATION_CODE));
}
}

// 다음버튼 누를 시, 인증성공하면 ? -> 비번 재설정 칸 생성 -> 완료 버튼
@Operation(summary = "비밀번호 재설정")
@PostMapping("/password")
public ResponseEntity<String> resetPassword(@RequestBody RequestResetPasswordVO request) {
log.info("POST /admin/password 요청 도착: request={}", request);

adminService.resetPassword(request);

log.info("비밀번호가 성공적으로 재설정되었습니다.");
return ResponseEntity.ok("비밀번호가 성공적으로 재설정되었습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package intbyte4.learnsmate.admin.domain.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import intbyte4.learnsmate.common.exception.CommonException;
import intbyte4.learnsmate.common.exception.ExceptionDTO;
import intbyte4.learnsmate.common.exception.StatusEnum;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class ResponseEmailDTO<T> {

@JsonIgnore
private HttpStatus httpStatus;

@NotNull
private boolean success;

@Nullable
private T data;

@Nullable
private ExceptionDTO error;

// static 팩토리 메소드
public static <T> ResponseEmailDTO<T> ok(T data) {
return new ResponseEmailDTO<>(
HttpStatus.OK,
true,
data,
null
);
}

public static ResponseEmailDTO<Object> fail(@NotNull CommonException e) {
return new ResponseEmailDTO<>(
e.getStatusEnum().getHttpStatus(),
false,
null,
ExceptionDTO.of(e.getStatusEnum())
);
}

public static ResponseEmailDTO<Object> fail(final MissingServletRequestParameterException e) {
return new ResponseEmailDTO<>(
HttpStatus.BAD_REQUEST,
false,
null,
ExceptionDTO.of(StatusEnum.MISSING_REQUEST_PARAMETER)
);
}

public static ResponseEmailDTO<Object> fail(final MethodArgumentTypeMismatchException e) {
return new ResponseEmailDTO<>(
HttpStatus.INTERNAL_SERVER_ERROR,
false,
null,
ExceptionDTO.of(StatusEnum.INVALID_PARAMETER_FORMAT)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@NoArgsConstructor
@ToString
@Getter
@Setter
@Builder
public class Admin {
@Id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package intbyte4.learnsmate.admin.domain.vo.request;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.*;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class AdminEmailVerificationVO {

@NotBlank
@Email
private String email;

@NotBlank
private Long adminCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package intbyte4.learnsmate.admin.domain.vo.request;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class EmailVerificationVO {

@NotBlank
@Email
private String email;

@NotBlank
private String code;

@NotBlank
private Long adminCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package intbyte4.learnsmate.admin.domain.vo.request;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class RequestResetPasswordVO {

@NotBlank
@Email
String userEmail;

@NotBlank
String userPassword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package intbyte4.learnsmate.admin.domain.vo.response;


import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class ResponseEmailMessageVO {

@JsonProperty("message")
private String message;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package intbyte4.learnsmate.admin.service;

import intbyte4.learnsmate.admin.domain.dto.AdminDTO;
import intbyte4.learnsmate.admin.domain.vo.request.RequestResetPasswordVO;
import org.springframework.security.core.userdetails.UserDetailsService;

public interface AdminService extends UserDetailsService {
AdminDTO findByAdminCode(Long adminCode);

AdminDTO updateAdmin(Long adminCode, AdminDTO editAdminVO);
AdminDTO updateAdmin(AdminDTO editAdminVO);

AdminDTO findUserByEmail(String adminEmail);

void resetPassword(RequestResetPasswordVO request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@
import intbyte4.learnsmate.admin.domain.dto.AdminDTO;
import intbyte4.learnsmate.admin.domain.entity.Admin;
import intbyte4.learnsmate.admin.domain.entity.CustomUserDetails;
import intbyte4.learnsmate.admin.domain.vo.request.RequestResetPasswordVO;
import intbyte4.learnsmate.admin.mapper.AdminMapper;
import intbyte4.learnsmate.admin.repository.AdminRepository;
import intbyte4.learnsmate.common.exception.CommonException;
import intbyte4.learnsmate.common.exception.StatusEnum;
import intbyte4.learnsmate.member.domain.MemberType;
import intbyte4.learnsmate.member.domain.dto.MemberDTO;
import intbyte4.learnsmate.member.mapper.MemberMapper;
import intbyte4.learnsmate.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
Expand All @@ -29,6 +27,7 @@
public class AdminServiceImpl implements AdminService {

private final AdminRepository adminRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final AdminMapper adminMapper;

@Override
Expand All @@ -38,8 +37,8 @@ public AdminDTO findByAdminCode(Long adminCode) {
}

@Override
public AdminDTO updateAdmin(Long adminCode, AdminDTO adminDTO) {
Admin admin = adminRepository.findById(adminCode)
public AdminDTO updateAdmin(AdminDTO adminDTO) {
Admin admin = adminRepository.findById(adminDTO.getAdminCode())
.orElseThrow(() -> new CommonException(StatusEnum.ADMIN_NOT_FOUND));
admin.toUpdate(adminDTO);
Admin updatedAdmin = adminRepository.save(admin);
Expand All @@ -65,5 +64,30 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
return new CustomUserDetails(adminDTO, grantedAuthorities, true, true, true, true);
}


@Override
public AdminDTO findUserByEmail(String adminEmail) {
Admin admin = adminRepository.findByAdminEmail(adminEmail);
if (admin == null) {
throw new CommonException(StatusEnum.ADMIN_NOT_FOUND);
}
return adminMapper.toDTO(admin);
}

@Override
public void resetPassword(RequestResetPasswordVO request) {

Admin admin = adminRepository.findByAdminEmail(request.getUserEmail());
if (admin == null) {
throw new CommonException(StatusEnum.ADMIN_NOT_FOUND);
}

// 비밀번호 bCrypt 암호화.
admin.setAdminPassword(bCryptPasswordEncoder.encode(request.getUserPassword()));

Admin updatedAdmin = adminRepository.save(admin);
adminMapper.toDTO(updatedAdmin);
}

}

Loading
Loading