From 8dd9977bbbe51e6792076ac2b262a89c78d16658 Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Wed, 7 Jan 2026 01:02:57 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kt/common/exception/ErrorCode.java | 8 ++ .../controller/certify/CertifyController.java | 38 +++++++++ .../java/com/kt/domain/certify/Certify.java | 80 +++++++++++++++++++ .../com/kt/domain/certify/CertifyStatus.java | 8 ++ .../certify/EmailCertificationRequest.java | 16 ++++ .../java/com/kt/dto/certify/EmailRequest.java | 13 +++ .../repository/certify/CertifyRepository.java | 10 +++ .../kt/repository/user/UserRepository.java | 1 + .../kt/service/certify/CertifyService.java | 78 ++++++++++++++++++ .../java/com/kt/service/user/UserService.java | 20 ++--- 10 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/kt/controller/certify/CertifyController.java create mode 100644 src/main/java/com/kt/domain/certify/Certify.java create mode 100644 src/main/java/com/kt/domain/certify/CertifyStatus.java create mode 100644 src/main/java/com/kt/dto/certify/EmailCertificationRequest.java create mode 100644 src/main/java/com/kt/dto/certify/EmailRequest.java create mode 100644 src/main/java/com/kt/repository/certify/CertifyRepository.java create mode 100644 src/main/java/com/kt/service/certify/CertifyService.java diff --git a/src/main/java/com/kt/common/exception/ErrorCode.java b/src/main/java/com/kt/common/exception/ErrorCode.java index 19d364ad..ec144f9a 100644 --- a/src/main/java/com/kt/common/exception/ErrorCode.java +++ b/src/main/java/com/kt/common/exception/ErrorCode.java @@ -27,6 +27,7 @@ public enum ErrorCode { DUPLICATED_LOGIN_ID(HttpStatus.BAD_REQUEST, "이미 존재하는 아이디입니다."), DOES_NOT_MATCH_OLD_PASSWORD(HttpStatus.BAD_REQUEST, "기존 비밀번호가 일치하지 않습니다."), CAN_NOT_ALLOWED_SAME_PASSWORD(HttpStatus.BAD_REQUEST, "기존 비밀번호와 동일한 비밀번호로 변경할 수 없습니다."), + DUPLICATED_EMAIL(HttpStatus.BAD_REQUEST, "중복되는 이메일입니다."), //product NOT_FOUND_PRODUCT(HttpStatus.BAD_REQUEST, "상품을 찾을 수 없습니다."), @@ -112,6 +113,13 @@ public enum ErrorCode { WISHLIST_ADD_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "찜 추가에 실패했습니다."), NOT_FOUND_WISHLIST(HttpStatus.BAD_REQUEST, "찜하지 않은 상품입니다."), + //certify + EXPIRED_CERTIFICATION_CODE(HttpStatus.BAD_REQUEST,"만료된 코드입니다."), + FAILED_MORE_THAN_FIVE_TIMES(HttpStatus.BAD_REQUEST,"5회이상 시도하여 잠금상태입니다."), + CERTIFICATION_CODE_NOT_FOUND(HttpStatus.BAD_REQUEST,"인증코드를 찾을 수 없습니다."), + INVALID_CERTIFICATION_CODE(HttpStatus.BAD_REQUEST,"틀린 코드입니다."), + NOT_VERIFIED_EMAIL(HttpStatus.BAD_REQUEST,"인증되지않은 이메일입니다."), + //vector NOT_FOUND_VECTOR_STORE(HttpStatus.BAD_REQUEST, "존재하지 않는 벡터 스토어입니다."), diff --git a/src/main/java/com/kt/controller/certify/CertifyController.java b/src/main/java/com/kt/controller/certify/CertifyController.java new file mode 100644 index 00000000..b3bd02c0 --- /dev/null +++ b/src/main/java/com/kt/controller/certify/CertifyController.java @@ -0,0 +1,38 @@ +package com.kt.controller.certify; + +import com.kt.common.response.ApiResult; +import com.kt.common.support.SwaggerAssistance; +import com.kt.dto.certify.EmailCertificationRequest; +import com.kt.dto.certify.EmailRequest; +import com.kt.service.certify.CertifyService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "Certify", description = "이메일 검증 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/certify") +public class CertifyController extends SwaggerAssistance{ + + private final CertifyService certifyService; + + @PostMapping("/code") + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "이메일 검증 코드 생성") + public ApiResult createCode(@RequestBody EmailRequest email){ + certifyService.createCode(email.email()); + return ApiResult.ok(); + } + + @PostMapping("/email") + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "코드를 통한 이메일 검증") + public ApiResult certify(@Valid @RequestBody EmailCertificationRequest emailCertificationRequest){ + certifyService.certifyEmail(emailCertificationRequest); + return ApiResult.ok(); + } +} diff --git a/src/main/java/com/kt/domain/certify/Certify.java b/src/main/java/com/kt/domain/certify/Certify.java new file mode 100644 index 00000000..7e5d0776 --- /dev/null +++ b/src/main/java/com/kt/domain/certify/Certify.java @@ -0,0 +1,80 @@ +package com.kt.domain.certify; + +import com.kt.common.support.BaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import java.time.LocalDateTime; + +@Entity +@Getter +@NoArgsConstructor +public class Certify extends BaseEntity { + + @Column(nullable = false) + private String email; + + @Column(nullable = false) + private String certifyCode; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private CertifyStatus codeStatus; + + @Column(nullable = false) + private int attempts; + + @Column(nullable = false) + private LocalDateTime expiresAt; + + private LocalDateTime lockedAt; + + private LocalDateTime verifiedAt; + + public void changeStatus(CertifyStatus codeStatus){ // 코드 사용여부등 상태확인용도 + this.codeStatus = codeStatus; + } + + public void initAttempts(){ // 시도횟수 초기화 + this.attempts = 0; + } + + public void increaseAttemptsAndLock() { + this.attempts++; + if (this.attempts >= 5) { + this.codeStatus = CertifyStatus.LOCKED; + this.lockedAt = LocalDateTime.now(); + } + } + + public static Certify create(String email, String code, LocalDateTime expire) { + Certify certify = new Certify(); + certify.email = email; + certify.certifyCode = code; + certify.codeStatus = CertifyStatus.PENDING; + certify.attempts = 0; + certify.expiresAt = expire; + return certify; + } + + public boolean isExpired(LocalDateTime now) { + return this.expiresAt.isBefore(now); + } + + public boolean isLocked() { + return this.codeStatus == CertifyStatus.LOCKED; + } + + public boolean isSameCode(String code) { + return this.certifyCode.equals(code); + } + + public boolean isVerified() { + if(this.expiresAt.equals(CertifyStatus.VERIFIED)){ + this.verifiedAt = LocalDateTime.now(); + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/kt/domain/certify/CertifyStatus.java b/src/main/java/com/kt/domain/certify/CertifyStatus.java new file mode 100644 index 00000000..74352623 --- /dev/null +++ b/src/main/java/com/kt/domain/certify/CertifyStatus.java @@ -0,0 +1,8 @@ +package com.kt.domain.certify; + +public enum CertifyStatus { + PENDING, + LOCKED, + VERIFIED, + EXPIRED +} diff --git a/src/main/java/com/kt/dto/certify/EmailCertificationRequest.java b/src/main/java/com/kt/dto/certify/EmailCertificationRequest.java new file mode 100644 index 00000000..57d26f98 --- /dev/null +++ b/src/main/java/com/kt/dto/certify/EmailCertificationRequest.java @@ -0,0 +1,16 @@ +package com.kt.dto.certify; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +public record EmailCertificationRequest( + @Schema(description = "이메일", example = "test@example.com") + @NotBlank + @Pattern(regexp = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$") + String email, + @NotNull + String code +) { +} diff --git a/src/main/java/com/kt/dto/certify/EmailRequest.java b/src/main/java/com/kt/dto/certify/EmailRequest.java new file mode 100644 index 00000000..768cb68e --- /dev/null +++ b/src/main/java/com/kt/dto/certify/EmailRequest.java @@ -0,0 +1,13 @@ +package com.kt.dto.certify; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; + +public record EmailRequest( + @Schema(description = "이메일", example = "test@example.com") + @NotBlank + @Pattern(regexp = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$") + String email +) { +} diff --git a/src/main/java/com/kt/repository/certify/CertifyRepository.java b/src/main/java/com/kt/repository/certify/CertifyRepository.java new file mode 100644 index 00000000..ad2755d0 --- /dev/null +++ b/src/main/java/com/kt/repository/certify/CertifyRepository.java @@ -0,0 +1,10 @@ +package com.kt.repository.certify; + +import com.kt.domain.certify.Certify; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + +public interface CertifyRepository extends JpaRepository { + Optional findTopByEmailOrderByCreatedAtDesc(String email); + +} diff --git a/src/main/java/com/kt/repository/user/UserRepository.java b/src/main/java/com/kt/repository/user/UserRepository.java index 4303f288..4c32a9f8 100644 --- a/src/main/java/com/kt/repository/user/UserRepository.java +++ b/src/main/java/com/kt/repository/user/UserRepository.java @@ -30,4 +30,5 @@ default User findByIdOrThrow(Long id, ErrorCode errorCode) { return findById(id).orElseThrow(() -> new CustomException(errorCode)); } Optional findByLoginId(String loginId); + Boolean existsByEmailAndIsDeletedFalse(String email); } diff --git a/src/main/java/com/kt/service/certify/CertifyService.java b/src/main/java/com/kt/service/certify/CertifyService.java new file mode 100644 index 00000000..79bc8732 --- /dev/null +++ b/src/main/java/com/kt/service/certify/CertifyService.java @@ -0,0 +1,78 @@ +package com.kt.service.certify; + +import com.kt.common.exception.CustomException; +import com.kt.common.exception.ErrorCode; +import com.kt.domain.certify.Certify; +import com.kt.domain.certify.CertifyStatus; +import com.kt.dto.certify.EmailCertificationRequest; +import com.kt.notification.MailSendRequest; +import com.kt.notification.MailSendService; +import com.kt.repository.certify.CertifyRepository; +import com.kt.repository.user.UserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Random; + +@RequiredArgsConstructor +@Service +public class CertifyService { + + private final UserRepository userRepository; + private final CertifyRepository certifyRepository; + private final MailSendService mailSendService; + @Transactional + public void certifyEmail(EmailCertificationRequest req) { + String email = req.email(); + LocalDateTime now = LocalDateTime.now(); + + if (userRepository.existsByEmailAndIsDeletedFalse(email)) { + throw new CustomException(ErrorCode.DUPLICATED_EMAIL); + } + + Certify certify = certifyRepository.findTopByEmailOrderByCreatedAtDesc(email) + .orElseThrow(() -> new CustomException(ErrorCode.CERTIFICATION_CODE_NOT_FOUND)); + + if (certify.isLocked()) { // 5회이상 틀릴시 잠금, 초과처럼 에러코드를 작성했지만 이상이 맞습니다... + throw new CustomException(ErrorCode.FAILED_MORE_THAN_FIVE_TIMES); + } + + if (certify.isExpired(now)) { // 코드 유효기간 만료 + certify.changeStatus(CertifyStatus.EXPIRED); + throw new CustomException(ErrorCode.EXPIRED_CERTIFICATION_CODE); + } + + if (certify.isSameCode(req.code())) { // 이메일 인증통과 + certify.changeStatus(CertifyStatus.VERIFIED); + certify.initAttempts(); + return; + } + + certify.increaseAttemptsAndLock(); // 실패시 틀림 처리 + throw new CustomException(ErrorCode.INVALID_CERTIFICATION_CODE); + } + + + @Transactional + public void createCode(String email) { // 인증을 위한 난수 생성, secureRandom을 통해 강한 난수를 생성할수도있다 -> 좀 과한 것 같으니 제외 + Random RANDOM = new Random(); + StringBuilder builder = new StringBuilder(6); + for (int i = 0; i < 6; i++) { + builder.append(RANDOM.nextInt(10)); // 0 ~ 9 + } + String code = builder.toString(); + LocalDateTime expire = LocalDateTime.now().plusMinutes(5L); + Certify certifyCode = Certify.create(email,code,expire); + certifyRepository.save(certifyCode); + + MailSendRequest request = new MailSendRequest( + email, + "이메일 인증 코드입니다.", + "코드: \n" + code + ); + mailSendService.sendEmail(request); + } + +} diff --git a/src/main/java/com/kt/service/user/UserService.java b/src/main/java/com/kt/service/user/UserService.java index afc04a69..b2fe2984 100644 --- a/src/main/java/com/kt/service/user/UserService.java +++ b/src/main/java/com/kt/service/user/UserService.java @@ -3,6 +3,7 @@ import com.kt.common.exception.CustomException; import com.kt.common.exception.ErrorCode; import com.kt.domain.auth.RefreshToken; +import com.kt.domain.certify.Certify; import com.kt.domain.membership.Membership; import com.kt.domain.shoppingaddress.ShoppingAddress; import com.kt.domain.user.Role; @@ -17,21 +18,13 @@ import com.kt.repository.user.UserRepository; import com.kt.security.CustomUserDetails; import com.kt.security.JwtTokenProvider; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; - -import java.time.Duration; -import java.time.Instant; import java.time.LocalDateTime; -import java.util.Date; import static com.kt.common.support.ObjectUtils.orElseIfEmpty; @@ -49,6 +42,7 @@ public class UserService { private static final String DEFAULT_MEMBERSHIP_LEVEL = "BRONZE"; private static final String BEARER_PREFIX = "Bearer "; private static final String AUTH_HEADER = "Authorization"; + private final Certify certify; public boolean checkLoginIdDuplicated(String loginId) { return userRepository.existsByLoginIdAndIsDeletedFalse(loginId); @@ -60,6 +54,9 @@ public void create(UserCreateRequest request) { if (checkLoginIdDuplicated(request.loginId())) { throw new CustomException(ErrorCode.DUPLICATED_LOGIN_ID); } + if(!certify.isVerified()){ + throw new CustomException(ErrorCode.NOT_VERIFIED_EMAIL); + } Membership defaultMembership = membershipRepository.findByLevel(DEFAULT_MEMBERSHIP_LEVEL) .orElseThrow(() -> new IllegalStateException("기본 멤버십이 설정되어 있지 않습니다.")); @@ -233,11 +230,4 @@ public void changeRole(UserChangeRole request){ user.changeRole(request.role()); } - private String resolveBearer(String request) { - if (request == null || !request.startsWith("Bearer ")) { - throw new CustomException(ErrorCode.INVALID_JWT_TOKEN); - } - - return request.substring(BEARER_PREFIX.length()); - } } From 7bba5944916f829ca3938d42f3455a85863b9fd3 Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Wed, 7 Jan 2026 01:38:20 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20verify=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD,=20is?= =?UTF-8?q?Verified=EC=97=90=20codeStatus=EA=B0=80=20=EC=95=84=EB=8B=8C=20?= =?UTF-8?q?expiresAt=EC=9D=B4=20=EB=B9=84=EA=B5=90=EA=B0=92=EC=97=90=20?= =?UTF-8?q?=EB=93=A4=EC=96=B4=EC=98=A8=20=EB=B6=80=EB=B6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20certify=20SecurityConfiguration=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,userservice=EC=97=90=EC=84=9C=20CertifyServi?= =?UTF-8?q?ce=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=B4=EC=84=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=ED=95=98=EB=8A=94=EA=B1=B8=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kt/config/SecurityConfiguration.java | 2 +- src/main/java/com/kt/domain/certify/Certify.java | 2 +- .../java/com/kt/service/certify/CertifyService.java | 11 +++++++++++ src/main/java/com/kt/service/user/UserService.java | 5 +++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/kt/config/SecurityConfiguration.java b/src/main/java/com/kt/config/SecurityConfiguration.java index a6a03a07..ccf920a9 100644 --- a/src/main/java/com/kt/config/SecurityConfiguration.java +++ b/src/main/java/com/kt/config/SecurityConfiguration.java @@ -28,7 +28,7 @@ public class SecurityConfiguration { private static final String[] GET_PERMIT_ALL = {"/api/health/**", "/swagger-ui.html","/swagger-ui/**", "/v3/api-docs/**", "/actuator/**", "/payment-*.html", "/api/payments/client-key", "/*.css", "/api/chats", "/api/chats/**"}; - private static final String[] POST_PERMIT_ALL = {"/api/users/auth/signup", "/api/users/auth/login","/api/admin/users/auth/signup", "/api/admin/users/auth/login","/api/users/reissue", "/api/payments/confirm"}; + private static final String[] POST_PERMIT_ALL = {"/api/users/auth/signup", "/api/users/auth/login","/api/admin/users/auth/signup", "/api/admin/users/auth/login","/api/users/reissue", "/api/payments/confirm","/api/certify/**"}; private static final String[] PUT_PERMIT_ALL = {"/api/v1/public/**"}; private static final String[] PATCH_PERMIT_ALL = {"/api/v1/public/**"}; private static final String[] DELETE_PERMIT_ALL = {"/api/v1/public/**"}; diff --git a/src/main/java/com/kt/domain/certify/Certify.java b/src/main/java/com/kt/domain/certify/Certify.java index 7e5d0776..f3899d0e 100644 --- a/src/main/java/com/kt/domain/certify/Certify.java +++ b/src/main/java/com/kt/domain/certify/Certify.java @@ -70,7 +70,7 @@ public boolean isSameCode(String code) { } public boolean isVerified() { - if(this.expiresAt.equals(CertifyStatus.VERIFIED)){ + if(this.codeStatus.equals(CertifyStatus.VERIFIED)){ this.verifiedAt = LocalDateTime.now(); return true; } diff --git a/src/main/java/com/kt/service/certify/CertifyService.java b/src/main/java/com/kt/service/certify/CertifyService.java index 79bc8732..00366c77 100644 --- a/src/main/java/com/kt/service/certify/CertifyService.java +++ b/src/main/java/com/kt/service/certify/CertifyService.java @@ -75,4 +75,15 @@ public void createCode(String email) { // 인증을 위한 난수 생성, secure mailSendService.sendEmail(request); } + public boolean validateEmailVerified(String email) { + Certify certify = certifyRepository.findTopByEmailOrderByCreatedAtDesc(email) + .orElseThrow(() -> new CustomException(ErrorCode.CERTIFICATION_CODE_NOT_FOUND)); + + if (certify.isVerified()) { + return true; + } + return false; + } + + } diff --git a/src/main/java/com/kt/service/user/UserService.java b/src/main/java/com/kt/service/user/UserService.java index b2fe2984..f537cdf8 100644 --- a/src/main/java/com/kt/service/user/UserService.java +++ b/src/main/java/com/kt/service/user/UserService.java @@ -18,6 +18,7 @@ import com.kt.repository.user.UserRepository; import com.kt.security.CustomUserDetails; import com.kt.security.JwtTokenProvider; +import com.kt.service.certify.CertifyService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -42,7 +43,7 @@ public class UserService { private static final String DEFAULT_MEMBERSHIP_LEVEL = "BRONZE"; private static final String BEARER_PREFIX = "Bearer "; private static final String AUTH_HEADER = "Authorization"; - private final Certify certify; + private final CertifyService certifyService; public boolean checkLoginIdDuplicated(String loginId) { return userRepository.existsByLoginIdAndIsDeletedFalse(loginId); @@ -54,7 +55,7 @@ public void create(UserCreateRequest request) { if (checkLoginIdDuplicated(request.loginId())) { throw new CustomException(ErrorCode.DUPLICATED_LOGIN_ID); } - if(!certify.isVerified()){ + if(!certifyService.validateEmailVerified(request.email())){ throw new CustomException(ErrorCode.NOT_VERIFIED_EMAIL); } Membership defaultMembership = membershipRepository.findByLevel(DEFAULT_MEMBERSHIP_LEVEL) From 23974456be9d7bfa591b1db7c2a9054465c08b69 Mon Sep 17 00:00:00 2001 From: DaveLee-b Date: Wed, 7 Jan 2026 02:04:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=9D=84=EC=9C=84=ED=95=9C=20verify=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kt/domain/certify/Certify.java | 13 +++++++++++++ .../com/kt/service/user/UserServiceTest.java | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kt/domain/certify/Certify.java b/src/main/java/com/kt/domain/certify/Certify.java index f3899d0e..aedbc946 100644 --- a/src/main/java/com/kt/domain/certify/Certify.java +++ b/src/main/java/com/kt/domain/certify/Certify.java @@ -76,5 +76,18 @@ public boolean isVerified() { } return false; } + public void markVerifiedForTest(LocalDateTime expiresAt) { + this.codeStatus = CertifyStatus.VERIFIED; + this.expiresAt = expiresAt; + } + public static Certify TestVerify(String email, String code, LocalDateTime expiresAt) { + Certify c = new Certify(); + c.email = email; + c.certifyCode = code; + c.codeStatus = CertifyStatus.PENDING; + c.expiresAt = expiresAt; + return c; + } + } \ No newline at end of file diff --git a/src/test/java/com/kt/service/user/UserServiceTest.java b/src/test/java/com/kt/service/user/UserServiceTest.java index 661e5024..2b1cc972 100644 --- a/src/test/java/com/kt/service/user/UserServiceTest.java +++ b/src/test/java/com/kt/service/user/UserServiceTest.java @@ -2,6 +2,8 @@ import com.kt.common.exception.CustomException; import com.kt.common.exception.ErrorCode; +import com.kt.domain.certify.Certify; +import com.kt.domain.certify.CertifyStatus; import com.kt.domain.membership.Membership; import com.kt.domain.user.Gender; import com.kt.domain.user.Role; @@ -9,6 +11,7 @@ import com.kt.dto.user.request.UserAdminUpdateRequest; import com.kt.dto.user.request.UserCreateRequest; import com.kt.dto.user.request.UserUpdateRequest; +import com.kt.repository.certify.CertifyRepository; import com.kt.repository.membership.MembershipRepository; import com.kt.repository.user.UserRepository; import com.kt.security.CustomUserDetails; @@ -19,11 +22,12 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.util.ReflectionTestUtils; import java.time.LocalDate; +import java.time.LocalDateTime; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,6 +37,12 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class UserServiceTest { + private void givenVerifiedEmail(String email) { + Certify certify = Certify.TestVerify(email, "000000", LocalDateTime.now().plusMinutes(10)); + certify.markVerifiedForTest(LocalDateTime.now().plusMinutes(10)); + certifyRepository.save(certify); + } + // 유저 유닛 테스트 작성 //테스트 환경 사전설정 @@ -42,6 +52,8 @@ class UserServiceTest { private UserRepository userRepository; @Autowired private MembershipRepository membershipRepository; + @Autowired + private CertifyRepository certifyRepository; @BeforeEach void setUp(){ @@ -66,8 +78,10 @@ void setUp(){ "BRONZE" ); + givenVerifiedEmail(request.email()); userService.create(request); + User savedUser = userRepository.findByLoginIdAndIsDeletedFalse(request.loginId()) .orElseThrow(() -> new IllegalStateException("유저가 저장되지 않았습니다.")); @@ -122,6 +136,7 @@ void setUp(){ "BRONZE" ); + givenVerifiedEmail(request.email()); userService.create(request); // 같은 loginId로 또 가입 시도하면 CustomException 발생 @@ -462,6 +477,7 @@ void setUp(){ LocalDate.of(2000, 1, 1), "BRONZE" ); + givenVerifiedEmail(request1.email()); userService.create(request1); User savedUser = userRepository.findByLoginIdAndIsDeletedFalse("rejoin_user") @@ -491,6 +507,7 @@ void setUp(){ ); + givenVerifiedEmail(request2.email()); userService.create(request2);