diff --git a/src/main/java/com/kboticketing/kboticketing/controller/UserController.java b/src/main/java/com/kboticketing/kboticketing/controller/UserController.java index f13e4c9..babfeed 100644 --- a/src/main/java/com/kboticketing/kboticketing/controller/UserController.java +++ b/src/main/java/com/kboticketing/kboticketing/controller/UserController.java @@ -2,6 +2,7 @@ import com.kboticketing.kboticketing.dto.EmailRequestDto; import com.kboticketing.kboticketing.dto.UserDto; +import com.kboticketing.kboticketing.dto.VerificationCodeDto; import com.kboticketing.kboticketing.service.UserService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -27,5 +28,10 @@ public void signUp(@RequestBody @Valid UserDto userDto) { public void sendVerificationCode(@RequestBody @Valid EmailRequestDto emailRequestDto) { userService.sendVerificationCode(emailRequestDto); } + + @PostMapping("verification-code-validation") + public void checkVerificationCode(@RequestBody @Valid VerificationCodeDto verificationCodeDto) { + userService.checkVerificationCode(verificationCodeDto); + } } diff --git a/src/main/java/com/kboticketing/kboticketing/dto/VerificationCodeDto.java b/src/main/java/com/kboticketing/kboticketing/dto/VerificationCodeDto.java new file mode 100644 index 0000000..a958860 --- /dev/null +++ b/src/main/java/com/kboticketing/kboticketing/dto/VerificationCodeDto.java @@ -0,0 +1,21 @@ +package com.kboticketing.kboticketing.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author hazel + */ +@Getter +@RequiredArgsConstructor +public class VerificationCodeDto { + + @NotBlank(message = "이메일을 입력해주세요.") + @Email(message = "이메일 형식이 아닙니다.") + private final String email; + + @NotBlank(message = "인증번호를 입력해주세요.") + private final String verificationCode; +} diff --git a/src/main/java/com/kboticketing/kboticketing/service/UserService.java b/src/main/java/com/kboticketing/kboticketing/service/UserService.java index 99af7d1..c488058 100644 --- a/src/main/java/com/kboticketing/kboticketing/service/UserService.java +++ b/src/main/java/com/kboticketing/kboticketing/service/UserService.java @@ -4,9 +4,11 @@ import com.kboticketing.kboticketing.domain.User; import com.kboticketing.kboticketing.dto.EmailRequestDto; import com.kboticketing.kboticketing.dto.UserDto; +import com.kboticketing.kboticketing.dto.VerificationCodeDto; import com.kboticketing.kboticketing.utils.EmailUtils; import com.kboticketing.kboticketing.utils.exception.CustomException; import com.kboticketing.kboticketing.utils.exception.ErrorCode; +import java.util.Objects; import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -31,7 +33,10 @@ public class UserService { private final RedisTemplate redisTemplate; public void signUp(UserDto userDto) { - //todo 인증번호 확인 로직 -> 인증번호 API 작업 후 작업 예정 + Boolean hasKey = redisTemplate.hasKey(userDto.getEmail()); + if (Boolean.FALSE.equals(hasKey)) { + throw new CustomException(ErrorCode.REQUEST_VERIFICATION_FIRST); + } if (!userDto.getPassword() .equals(userDto.getConfirmedPassword())) { @@ -62,6 +67,19 @@ public void sendVerificationCode(EmailRequestDto emailRequestDto) { emailUtil.sendEmail(verificationCode, emailRequestDto.getEmail()); } + + public void checkVerificationCode(VerificationCodeDto verificationCodeDto) { + Boolean hasKey = redisTemplate.hasKey(verificationCodeDto.getEmail()); + if (Boolean.FALSE.equals(hasKey)) { + throw new CustomException(ErrorCode.REQUEST_VERIFICATION_FIRST); + } + + String storedVerificationCode = redisTemplate.opsForValue() + .get(verificationCodeDto.getEmail()); + if (!Objects.equals(verificationCodeDto.getVerificationCode(), storedVerificationCode)) { + throw new CustomException(ErrorCode.WRONG_VERIFICATION_CODE); + } + } } diff --git a/src/main/java/com/kboticketing/kboticketing/utils/exception/ErrorCode.java b/src/main/java/com/kboticketing/kboticketing/utils/exception/ErrorCode.java index 4f7df13..a210ff1 100644 --- a/src/main/java/com/kboticketing/kboticketing/utils/exception/ErrorCode.java +++ b/src/main/java/com/kboticketing/kboticketing/utils/exception/ErrorCode.java @@ -16,10 +16,12 @@ public enum ErrorCode { PASSWORD_MISMATCH(HttpStatus.BAD_REQUEST, "두 비밀번호가 일치하지 않습니다."), EMAIL_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "이미 존재하는 이메일입니다."), FREQUENT_VERIFICATION_REQUEST(HttpStatus.BAD_REQUEST, "잦은 인증번호 요청은 불가능합니다."), + REQUEST_VERIFICATION_FIRST(HttpStatus.BAD_REQUEST, "인증을 먼저 진행해주세요."), + WRONG_VERIFICATION_CODE(HttpStatus.BAD_REQUEST, "인증번호가 다릅니다."), /* 500 INTERNAL_SERVER_ERROR : 서버 오류 */ FAIL_SEND_EMAIL(HttpStatus.INTERNAL_SERVER_ERROR, "이메일 전송에 실패하였습니다."); private final HttpStatus httpStatus; private final String message; -} +} \ No newline at end of file diff --git a/src/test/java/com/kboticketing/kboticketing/controller/UserControllerTest.java b/src/test/java/com/kboticketing/kboticketing/controller/UserControllerTest.java index 9952e22..e192cd5 100644 --- a/src/test/java/com/kboticketing/kboticketing/controller/UserControllerTest.java +++ b/src/test/java/com/kboticketing/kboticketing/controller/UserControllerTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.kboticketing.kboticketing.dto.EmailRequestDto; import com.kboticketing.kboticketing.dto.UserDto; +import com.kboticketing.kboticketing.dto.VerificationCodeDto; import com.kboticketing.kboticketing.service.UserService; import com.kboticketing.kboticketing.utils.exception.CustomException; import com.kboticketing.kboticketing.utils.exception.ErrorCode; @@ -112,7 +113,7 @@ void sendVerificationEmailInputTest() throws Exception { } @Test - @DisplayName("[FAIL] 이메일 유효성 검증 태스트") + @DisplayName("[FAIL] 이메일 유효성 검증 테스트") void sendVerificationEmailValidTest() throws Exception { //given @@ -125,4 +126,37 @@ void sendVerificationEmailValidTest() throws Exception { .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()); } + + @Test + @DisplayName("[SUCCESS] 인증번호 확인 테스트") + void checkVerificationCodeTest() throws Exception { + + //given + VerificationCodeDto verificationCodeDto = new VerificationCodeDto("aaaa@naver.com", + "123123"); + String json = new ObjectMapper().writeValueAsString(verificationCodeDto); + + //when, then + mockMvc.perform(post("/verification-code-validation") + .content(json) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + + @Test + @DisplayName("[FAIL] 인증번호 미입력 테스트") + public void checkVerificationCodeValidationTest() throws Exception { + + //given + VerificationCodeDto verificationCodeDto = new VerificationCodeDto("aaaa@naver.com", + ""); + String json = new ObjectMapper().writeValueAsString(verificationCodeDto); + + //when, then + mockMvc.perform(post("/verification-code-validation") + .content(json) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()); + } } \ No newline at end of file diff --git a/src/test/java/com/kboticketing/kboticketing/service/UserServiceTest.java b/src/test/java/com/kboticketing/kboticketing/service/UserServiceTest.java index b98863a..e0c6f4b 100644 --- a/src/test/java/com/kboticketing/kboticketing/service/UserServiceTest.java +++ b/src/test/java/com/kboticketing/kboticketing/service/UserServiceTest.java @@ -10,6 +10,7 @@ import com.kboticketing.kboticketing.domain.User; import com.kboticketing.kboticketing.dto.EmailRequestDto; import com.kboticketing.kboticketing.dto.UserDto; +import com.kboticketing.kboticketing.dto.VerificationCodeDto; import com.kboticketing.kboticketing.utils.EmailUtils; import com.kboticketing.kboticketing.utils.enums.Role; import com.kboticketing.kboticketing.utils.exception.CustomException; @@ -18,7 +19,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.BDDMockito; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -49,6 +49,7 @@ public void signUpSuccessTest() { // given UserDto userDto = new UserDto("홍길동", "aaa@naver.com", "123123", "123123", "123123"); given(userMapper.selectByEmail(any())).willReturn(null); + given(redisTemplate.hasKey(anyString())).willReturn(true); //when, then : 아무런 예외를 던지지 않음. assertDoesNotThrow(() -> userService.signUp(userDto)); @@ -60,6 +61,7 @@ public void signUpPasswordMismatchTest() { //given UserDto userDto = new UserDto("홍길동", "aaa@naver.com", "123123", "123123", "000000"); + given(redisTemplate.hasKey(anyString())).willReturn(true); // when CustomException customException = assertThrows(CustomException.class, () -> { @@ -77,8 +79,8 @@ public void signUpEmailCheckTest() { //given UserDto userDto = new UserDto("홍길동", "aaa@naver.com", "123123", "123123", "123123"); User user = new User("홍길동", "aaa@naver.com", "123123", Role.USER, LocalDateTime.now()); - BDDMockito.given(userMapper.selectByEmail(userDto.getEmail())) - .willReturn(user); + given(userMapper.selectByEmail(userDto.getEmail())).willReturn(user); + given(redisTemplate.hasKey(anyString())).willReturn(true); //when CustomException customException = assertThrows(CustomException.class, () -> { @@ -123,6 +125,43 @@ public void sendVerificationAgainFailTest() { assertThat(customException.getErrorCode()).isEqualTo( ErrorCode.FREQUENT_VERIFICATION_REQUEST); } + + @Test + @DisplayName("[SUCCESS] 인증번호 확인 테스트") + public void checkVerificationCodeTest() { + + //given + VerificationCodeDto verificationCodeDto = new VerificationCodeDto("aaa@naver.com", + "123456"); + given(redisTemplate.hasKey(anyString())).willReturn(true); + given(redisTemplate.opsForValue()).willReturn(valueOperations); + given(redisTemplate.opsForValue() + .get(verificationCodeDto.getEmail())).willReturn("123456"); + + //when,then + assertDoesNotThrow(() -> userService.checkVerificationCode(verificationCodeDto)); + } + + @Test + @DisplayName("[FAIL] 인증번호 불일치 테스트") + public void checkVerificationCodeWrongTest() { + + //given + VerificationCodeDto verificationCodeDto = new VerificationCodeDto("aaa@naver.com", + "123456"); + given(redisTemplate.hasKey(anyString())).willReturn(true); + given(redisTemplate.opsForValue()).willReturn(valueOperations); + given(redisTemplate.opsForValue() + .get(verificationCodeDto.getEmail())).willReturn("999999"); + + //when + CustomException customException = assertThrows(CustomException.class, () -> { + userService.checkVerificationCode(verificationCodeDto); + }); + + //then + assertThat(customException.getErrorCode()).isEqualTo(ErrorCode.WRONG_VERIFICATION_CODE); + } }