diff --git a/build.gradle b/build.gradle index 0dbf780..34cd662 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,8 @@ dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' implementation "com.amazonaws:aws-java-sdk-s3:1.12.395" + // Redis + implementation 'org.springframework.boot:spring-boot-starter-data-redis' // Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' diff --git a/src/main/java/servnow/servnow/api/auth/controller/FindController.java b/src/main/java/servnow/servnow/api/auth/controller/FindController.java index 0633ad2..9f629f8 100644 --- a/src/main/java/servnow/servnow/api/auth/controller/FindController.java +++ b/src/main/java/servnow/servnow/api/auth/controller/FindController.java @@ -7,7 +7,7 @@ import servnow.servnow.api.dto.login.UserChangePwRequest; import servnow.servnow.api.user.dto.request.CertificationNumberRequest; import servnow.servnow.api.user.dto.request.EmailDuplicateRequest; -import servnow.servnow.api.user.service.EmailService; +import servnow.servnow.api.user.service.EmailQueryService; import servnow.servnow.api.user.service.UserCommandService; import servnow.servnow.api.user.service.UserQueryService; import servnow.servnow.common.code.CommonSuccessCode; @@ -15,7 +15,6 @@ import servnow.servnow.common.code.UserErrorCode; import servnow.servnow.domain.user.model.User; import servnow.servnow.domain.user.model.enums.Platform; -import servnow.servnow.domain.user.repository.UserInfoRepository; import servnow.servnow.domain.user.repository.UserRepository; import java.util.Optional; @@ -29,6 +28,7 @@ public class FindController { private final UserCommandService userCommandService; private final UserQueryService userQueryService; private final UserRepository userRepository; + private final EmailQueryService emailQueryService; String serialId = null; Boolean check = false; @@ -61,7 +61,9 @@ public ServnowResponse sendEmailNumber(@RequestBody EmailDuplicateReques @PostMapping("/find/email/certification") public ServnowResponse CertificationNumber(@RequestBody CertificationNumberRequest request) { - if (request.certificationNumber().equals(EmailService.ePw)) { + boolean isVallid = emailQueryService.verifyCode(request.email(), request.certificationNumber()); + + if (isVallid) { check = true; return ServnowResponse.success(CommonSuccessCode.OK, serialId); } else { diff --git a/src/main/java/servnow/servnow/api/auth/controller/LoginController.java b/src/main/java/servnow/servnow/api/auth/controller/LoginController.java index f0b4d69..47e600f 100644 --- a/src/main/java/servnow/servnow/api/auth/controller/LoginController.java +++ b/src/main/java/servnow/servnow/api/auth/controller/LoginController.java @@ -1,6 +1,5 @@ package servnow.servnow.api.auth.controller; -import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; @@ -15,15 +14,13 @@ import servnow.servnow.api.user.dto.request.CertificationNumberRequest; import servnow.servnow.api.user.dto.request.EmailDuplicateRequest; import servnow.servnow.api.user.dto.request.SerialIdDuplicateRequest; -import servnow.servnow.api.user.service.EmailService; +import servnow.servnow.api.user.service.EmailCommandService; +import servnow.servnow.api.user.service.EmailQueryService; import servnow.servnow.api.user.service.UserQueryService; import servnow.servnow.auth.UserId; -import servnow.servnow.auth.jwt.Token; import servnow.servnow.common.code.CommonSuccessCode; import servnow.servnow.common.code.UserErrorCode; -import java.io.IOException; - @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") @@ -32,6 +29,8 @@ public class LoginController { private final KakaoService kakaoService; private final LoginService loginService; private final UserQueryService userQueryService; + private final EmailQueryService emailQueryService; + private final EmailCommandService emailCommandService; // 카카오 로그인 @PostMapping("/auth/kakao") @@ -59,7 +58,7 @@ public ServnowResponse login(@RequestBody UserLoginRequest re @PostMapping("/auth/join") public ServnowResponse join(@RequestBody UserJoinRequest request) throws Exception { if (request.email() != null && !request.email().isEmpty() && - request.certificationNumber() != null && request.certificationNumber().equals(EmailService.ePw)) { + request.certificationNumber() != null && emailQueryService.verifyCode(request.email(), request.certificationNumber())) { loginService.join(request); return ServnowResponse.success(CommonSuccessCode.OK, "회원가입이 완료되었습니다."); } else { @@ -70,13 +69,15 @@ public ServnowResponse join(@RequestBody UserJoinRequest request) throws // 회원가입 - 이메일 인증 @PostMapping("/auth/join/identity-verification") public ServnowResponse identityVerification(@RequestBody EmailDuplicateRequest request) throws Exception { - return userQueryService.identityVerification(request.email()); + emailCommandService.sendVerificationEmail(request.email()); + return ServnowResponse.success(CommonSuccessCode.OK); } // 회원가입 - 인증 번호 확인 @PostMapping("/auth/join/certification") public ServnowResponse CertificationNumber(@RequestBody CertificationNumberRequest request) { - if (request.certificationNumber().equals(EmailService.ePw)) { + boolean isVerified = emailQueryService.verifyCode(request.email(), request.certificationNumber()); + if (isVerified) { return ServnowResponse.success(CommonSuccessCode.OK); } else { return ServnowResponse.fail(UserErrorCode.CERTIFICATION_NUMBER_MISMATCH); diff --git a/src/main/java/servnow/servnow/api/auth/service/FindInfoService.java b/src/main/java/servnow/servnow/api/auth/service/FindInfoService.java index e932c4f..5a4b6e8 100644 --- a/src/main/java/servnow/servnow/api/auth/service/FindInfoService.java +++ b/src/main/java/servnow/servnow/api/auth/service/FindInfoService.java @@ -1,12 +1,10 @@ package servnow.servnow.api.auth.service; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import servnow.servnow.api.dto.ServnowResponse; -import servnow.servnow.api.user.service.EmailService; +import servnow.servnow.api.user.service.EmailCommandService; import servnow.servnow.common.code.CommonSuccessCode; import servnow.servnow.common.code.LoginErrorCode; import servnow.servnow.common.code.UserErrorCode; @@ -23,8 +21,8 @@ public class FindInfoService { private final UserRepository userRepository; private final UserInfoRepository userInfoRepository; - private final EmailService emailService; private final PasswordEncoder passwordEncoder; + private final EmailCommandService emailCommandService; /** * 이메일 존재 여부 확인 @@ -33,7 +31,7 @@ public String checkEmail(String email) throws Exception { Optional userInfo = userInfoRepository.findByEmail(email); if (userInfo.isPresent()) { - String confirm = emailService.sendSimpleMessage(email); + String confirm = emailCommandService.sendVerificationEmail(email); String serialId = userInfo.get().getUser().getSerialId(); if (confirm.isEmpty()) { diff --git a/src/main/java/servnow/servnow/api/config/RedisConfig.java b/src/main/java/servnow/servnow/api/config/RedisConfig.java new file mode 100644 index 0000000..958397a --- /dev/null +++ b/src/main/java/servnow/servnow/api/config/RedisConfig.java @@ -0,0 +1,33 @@ +package servnow.servnow.api.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Value("${spring.data.redis.host}") + private String redisHost; + + @Value("${spring.data.redis.port}") + private int redisPort; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(redisHost, redisPort); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + return redisTemplate; + } +} diff --git a/src/main/java/servnow/servnow/api/user/controller/UserController.java b/src/main/java/servnow/servnow/api/user/controller/UserController.java index 5683fec..84b4f36 100644 --- a/src/main/java/servnow/servnow/api/user/controller/UserController.java +++ b/src/main/java/servnow/servnow/api/user/controller/UserController.java @@ -27,7 +27,8 @@ import servnow.servnow.api.user.dto.response.MySurveyResponse; import servnow.servnow.api.survey.service.SurveyQueryService; import servnow.servnow.api.user.dto.response.UserPointGetResponse; -import servnow.servnow.api.user.service.EmailService; +import servnow.servnow.api.user.service.EmailCommandService; +import servnow.servnow.api.user.service.EmailQueryService; import servnow.servnow.api.user.service.UserCommandService; import servnow.servnow.api.user.service.UserQueryService; import servnow.servnow.auth.UserId; @@ -46,17 +47,18 @@ public class UserController { private final ResultQueryService resultQueryService; private final ResultCommandService resultCommandService; private final SurveyQueryService surveyQueryService; - + private final EmailCommandService emailCommandService; + private final EmailQueryService emailQueryService; // 아직 유저 정보를 넘기는 방식이 정해지지 않아서 UserQueryService에서 userId값을 고정하여 테스트 함 @GetMapping("/users/me") - public ServnowResponse getMyPage(@Parameter (hidden = true) @UserId final Long userId) { + public ServnowResponse getMyPage(@Parameter(hidden = true) @UserId final Long userId) { return ServnowResponse.success(CommonSuccessCode.OK, userQueryService.getMyPage(userId)); } @GetMapping("/users/me/info") - public ServnowResponse getEditProfilePage(@Parameter (hidden = true) @UserId final Long userId) { + public ServnowResponse getEditProfilePage(@Parameter(hidden = true) @UserId final Long userId) { return ServnowResponse.success(CommonSuccessCode.OK, userQueryService.getEditProfilePage(userId)); } @@ -67,12 +69,17 @@ public ServnowResponse getSerialIdDuplicate(@RequestBody SerialIdDuplic @PostMapping("/users/me/info/identity-verification") public ServnowResponse identityVerification(@RequestBody EmailDuplicateRequest request) throws Exception { - return userQueryService.identityVerification(request.email()); + if (userQueryService.emailDuplicate(request.email())) { + return ServnowResponse.fail(UserErrorCode.EMAIL_DUPLICATE); + } + emailCommandService.sendVerificationEmail(request.email()); + return ServnowResponse.success(CommonSuccessCode.OK); } @PostMapping("/users/me/info/certification") public ServnowResponse CertificationNumber(@RequestBody CertificationNumberRequest request) { - if (request.certificationNumber().equals(EmailService.ePw)) { + boolean isValid = emailQueryService.verifyCode(request.email(), request.certificationNumber()); + if (isValid) { return ServnowResponse.success(CommonSuccessCode.OK); } else { return ServnowResponse.fail(UserErrorCode.CERTIFICATION_NUMBER_MISMATCH); @@ -87,57 +94,69 @@ public ServnowResponse updateProfile(@RequestParam("fil @PatchMapping("/users/me/info/save") - public ServnowResponse profileSave(@Parameter (hidden = true) @UserId final Long userId, @RequestBody final SaveEditProfilePageRequest request) { + public ServnowResponse profileSave(@Parameter(hidden = true) @UserId final Long userId, @RequestBody final SaveEditProfilePageRequest request) { // 이메일이 변경되었고, 인증번호가 있는 경우 - if (request.email() != null && !request.email().isEmpty() && - request.certificationNumber() != null && request.certificationNumber().equals(EmailService.ePw)) { - userCommandService.profileSave(userId, request); - return ServnowResponse.success(CommonSuccessCode.OK); - } else if ((request.certificationNumber() == null) || request.certificationNumber().isEmpty()) { - // 인증번호 없이 아이디 또는 비밀번호만 변경하려는 경우 - userCommandService.profileSave(userId, request); - return ServnowResponse.success(CommonSuccessCode.OK); - } else { - System.out.println("Controller out"); - return ServnowResponse.fail(UserErrorCode.CERTIFICATION_NUMBER_MISMATCH); + if (request.email() != null && !request.email().isEmpty()) { + if (request.certificationNumber() != null && !request.certificationNumber().isEmpty()) { + boolean isValid = emailQueryService.verifyCode(request.email(), request.certificationNumber()); + + if (!isValid) { + return ServnowResponse.fail(UserErrorCode.CERTIFICATION_NUMBER_MISMATCH); + } + userCommandService.profileSave(userId, request); + return ServnowResponse.success(CommonSuccessCode.OK); + } else { + // 이메일 변경, 인증번호가 없는 경우 + return ServnowResponse.fail(UserErrorCode.CERTIFICATION_NUMBER_REQUIRED); + } } + // 이메일이 변경되지 않은 경우 + userCommandService.profileSave(userId, request); + return ServnowResponse.success(CommonSuccessCode.OK); } @GetMapping("/users/me/survey/{id}") - public ServnowResponse getMySurveysResult(@Parameter (hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { + public ServnowResponse getMySurveysResult( + @Parameter(hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { MySurveysResultResponse result = resultQueryService.getMySurveysResult(surveyId); return ServnowResponse.success(CommonSuccessCode.OK, result); } // 나의 닫ㅂ변 @GetMapping("/users/me/survey/{id}/answer") - public ServnowResponse getMyAnswersResult(@Parameter (hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { + public ServnowResponse getMyAnswersResult( + @Parameter(hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { UserSurveyAnswerResultResponse result = resultQueryService.getMyAnswerResult(surveyId, userId); return ServnowResponse.success(CommonSuccessCode.OK, result); } @PostMapping("/users/me/survey/{id}/memo") - public ServnowResponse saveInsightMemo(@Parameter (hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId, @RequestBody final MySurveysResultMemoRequest request) { + public ServnowResponse saveInsightMemo(@Parameter(hidden = true) @UserId final Long userId, + @PathVariable(name = "id") long surveyId, @RequestBody final MySurveysResultMemoRequest request) { resultCommandService.saveInsightMemo(surveyId, request); return ServnowResponse.success(CommonSuccessCode.OK); } @GetMapping("/users/me/survey/{id}/memo/list") - public ServnowResponse getInsightMemo(@Parameter (hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { + public ServnowResponse getInsightMemo( + @Parameter(hidden = true) @UserId final Long userId, @PathVariable(name = "id") long surveyId) { MySurveysResultMemoResponse result = resultQueryService.getInsightMemo(surveyId); return ServnowResponse.success(CommonSuccessCode.OK, result); } @GetMapping("/users/me/survey") // sort=newest, sort=oldest, sort=participants - public ServnowResponse> getMySurveys(@Parameter (hidden = true) @UserId final Long userId, @RequestParam(value = "sort", required = false, defaultValue = "newest") String sort) { + public ServnowResponse> getMySurveys( + @Parameter(hidden = true) @UserId final Long userId, + @RequestParam(value = "sort", required = false, defaultValue = "newest") String sort) { List surveys = surveyQueryService.getMySurveys(userId, sort); return ServnowResponse.success(CommonSuccessCode.OK, surveys); } @GetMapping("/users/me/survey/join") - public ServnowResponse> getJoinSurveys(@Parameter(hidden = true) @UserId final Long userId, - @RequestParam(value = "sort", required = false, defaultValue = "newest") String sort) { + public ServnowResponse> getJoinSurveys( + @Parameter(hidden = true) @UserId final Long userId, + @RequestParam(value = "sort", required = false, defaultValue = "newest") String sort) { List surveys = resultQueryService.getJoinSurveys(userId, sort); return ServnowResponse.success(CommonSuccessCode.OK, surveys); } @@ -153,8 +172,9 @@ public ServnowResponse deleteSurveyMemo(@PathVariable(name = "id") Long id return ServnowResponse.success(CommonSuccessCode.OK); } - @PatchMapping ("/users/me/survey/memo") - public ServnowResponse updateSurveyMemos(@RequestBody SurveyResultMemosPatchRequest surveyResultMemosPatchRequest) { + @PatchMapping("/users/me/survey/memo") + public ServnowResponse updateSurveyMemos(@RequestBody SurveyResultMemosPatchRequest + surveyResultMemosPatchRequest) { resultCommandService.updateSurveyMemos(surveyResultMemosPatchRequest); return ServnowResponse.success(CommonSuccessCode.OK); } diff --git a/src/main/java/servnow/servnow/api/user/dto/request/CertificationNumberRequest.java b/src/main/java/servnow/servnow/api/user/dto/request/CertificationNumberRequest.java index 03f8fce..fb73b74 100644 --- a/src/main/java/servnow/servnow/api/user/dto/request/CertificationNumberRequest.java +++ b/src/main/java/servnow/servnow/api/user/dto/request/CertificationNumberRequest.java @@ -1,6 +1,7 @@ package servnow.servnow.api.user.dto.request; public record CertificationNumberRequest( + String email, String certificationNumber ) { } diff --git a/src/main/java/servnow/servnow/api/user/service/EmailCodeGenerator.java b/src/main/java/servnow/servnow/api/user/service/EmailCodeGenerator.java new file mode 100644 index 0000000..f9b2e9d --- /dev/null +++ b/src/main/java/servnow/servnow/api/user/service/EmailCodeGenerator.java @@ -0,0 +1,21 @@ +package servnow.servnow.api.user.service; + +import org.springframework.stereotype.Component; +import java.util.Random; + +@Component +public class EmailCodeGenerator { + + private static final String CHAR_POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + public String generateCode() { + StringBuilder code = new StringBuilder(); + Random rnd = new Random(); + + for (int i = 0; i < 8; i++) { + code.append(CHAR_POOL.charAt(rnd.nextInt(CHAR_POOL.length()))); + } + + return code.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/servnow/servnow/api/user/service/EmailCommandService.java b/src/main/java/servnow/servnow/api/user/service/EmailCommandService.java new file mode 100644 index 0000000..dbed53b --- /dev/null +++ b/src/main/java/servnow/servnow/api/user/service/EmailCommandService.java @@ -0,0 +1,58 @@ +package servnow.servnow.api.user.service; + +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.mail.MailException; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Service; +import servnow.servnow.common.code.UserErrorCode; +import servnow.servnow.common.exception.NotFoundException; + +@Service +@RequiredArgsConstructor +public class EmailCommandService { + + private final JavaMailSender emailSender; + private final EmailVerificationService emailVerificationService; + private final EmailCodeGenerator emailCodeGenerator; + + public String sendVerificationEmail(String email) throws Exception { + String code = emailCodeGenerator.generateCode(); + + // Redis에 인증번호 저장 + emailVerificationService.saveVerificationCode(email, code); + + // 이메일 발송 + MimeMessage message = createMessage(email, code); + try { + emailSender.send(message); + } catch (MailException e) { + throw new NotFoundException(UserErrorCode.SEND_CERTIFICATION_NUMBER); + } + + return code; + } + + private MimeMessage createMessage(String to, String code) throws Exception { + MimeMessage message = emailSender.createMimeMessage(); + message.addRecipients(MimeMessage.RecipientType.TO, to); + message.setSubject("이메일 인증 코드"); + + String msgg = getMsgg(code); + message.setText(msgg, "utf-8", "html"); + message.setFrom(new InternetAddress("SERVNOW@gmail.com", "SERVNOW")); + + return message; + } + + private String getMsgg(String code) { + return "
" + + "

SERVNOW

" + + "

아래 코드를 복사해 입력해주세요

" + + "
" + + "

이메일 인증 코드

" + + "

" + code + "

" + + "
"; + } +} diff --git a/src/main/java/servnow/servnow/api/user/service/EmailQueryService.java b/src/main/java/servnow/servnow/api/user/service/EmailQueryService.java new file mode 100644 index 0000000..a1b70b5 --- /dev/null +++ b/src/main/java/servnow/servnow/api/user/service/EmailQueryService.java @@ -0,0 +1,15 @@ +package servnow.servnow.api.user.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class EmailQueryService { + + private final EmailVerificationService emailVerificationService; + + public boolean verifyCode(String email, String inputCode) { + return emailVerificationService.verifyCode(email, inputCode); + } +} diff --git a/src/main/java/servnow/servnow/api/user/service/EmailService.java b/src/main/java/servnow/servnow/api/user/service/EmailService.java deleted file mode 100644 index d39061d..0000000 --- a/src/main/java/servnow/servnow/api/user/service/EmailService.java +++ /dev/null @@ -1,89 +0,0 @@ -package servnow.servnow.api.user.service; - -import jakarta.mail.internet.InternetAddress; -import jakarta.mail.internet.MimeMessage; -import org.springframework.mail.MailException; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.stereotype.Service; - -import java.util.Random; - -@Service -public class EmailService { - - private final JavaMailSender emailSender; - - public static final String ePw = createKey(); - - public EmailService(JavaMailSender emailSender) { - this.emailSender = emailSender; - } - - private MimeMessage createMessage(String to) throws Exception { - System.out.println("보내는 대상 : " + to); - System.out.println("인증 번호 : " + ePw); - MimeMessage message = emailSender.createMimeMessage(); - message.addRecipients(MimeMessage.RecipientType.TO, to);//보내는 대상 - message.setSubject("이메일 인증 테스트");//제목 - - String msgg = getMsgg(); - message.setText(msgg, "utf-8", "html");//내용 - message.setFrom(new InternetAddress("SERVNOW@gmail.com", "SERVNOW"));//보내는 사람 - - return message; - } - - private static String getMsgg() { - String msgg = ""; - msgg += "
"; - msgg += "

SERVNOW

"; - msgg += "
"; - msgg += "

아래 코드를 복사해 입력해주세요

"; - msgg += "
"; - msgg += "

감사합니다.

"; - msgg += "
"; - msgg += "

"; - msgg += "

이메일 인증 코드입니다.

"; - msgg += "
"; - msgg += "CODE : "; - msgg += ePw + "

"; - msgg += "
"; - return msgg; - } - - public static String createKey() { - StringBuilder key = new StringBuilder(); - Random rnd = new Random(); - - for (int i = 0; i < 8; i++) { // 인증코드 8자리 - int index = rnd.nextInt(3); // 0~2 까지 랜덤 - - switch (index) { - case 0: - key.append((char) (rnd.nextInt(26) + 97)); - // a~z (ex. 1+97=98 => (char)98 = 'b') - break; - case 1: - key.append((char) (rnd.nextInt(26) + 65)); - // A~Z - break; - case 2: - key.append((rnd.nextInt(10))); - // 0~9 - break; - } - } - return key.toString(); - } - - public String sendSimpleMessage(String to) throws Exception { - // TODO Auto-generated method stub - MimeMessage message = createMessage(to); - try {//예외처리 - emailSender.send(message); - } catch (MailException es) { - throw new IllegalArgumentException("Failed to send email", es); - } - return ePw; - } -} diff --git a/src/main/java/servnow/servnow/api/user/service/EmailVerificationService.java b/src/main/java/servnow/servnow/api/user/service/EmailVerificationService.java new file mode 100644 index 0000000..ce59579 --- /dev/null +++ b/src/main/java/servnow/servnow/api/user/service/EmailVerificationService.java @@ -0,0 +1,28 @@ +package servnow.servnow.api.user.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +@Service +@RequiredArgsConstructor +public class EmailVerificationService { + + private final RedisTemplate redisTemplate; + private static final long EXPIRATION_TIME = 5 * 60; // 5분 + + public void saveVerificationCode(String email, String code) { + redisTemplate.opsForValue().set(buildKey(email), code, EXPIRATION_TIME, TimeUnit.SECONDS); + } + + public boolean verifyCode(String email, String inputCode) { + String storedCode = redisTemplate.opsForValue().get(buildKey(email)); + return storedCode != null && storedCode.equals(inputCode); + } + + private String buildKey(String email) { + return "email:verification:" + email; + } +} diff --git a/src/main/java/servnow/servnow/api/user/service/UserCommandService.java b/src/main/java/servnow/servnow/api/user/service/UserCommandService.java index 5ffcc24..dd97dd5 100644 --- a/src/main/java/servnow/servnow/api/user/service/UserCommandService.java +++ b/src/main/java/servnow/servnow/api/user/service/UserCommandService.java @@ -1,13 +1,10 @@ package servnow.servnow.api.user.service; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import servnow.servnow.api.result.service.surveyresultmemo.SurveyResultMemoFinder; -import servnow.servnow.api.result.service.surveyresultmemo.SurveyResultMemoUpdater; import servnow.servnow.api.user.dto.request.SaveEditProfilePageRequest; -import servnow.servnow.common.code.SuccessCode; import servnow.servnow.common.code.UserErrorCode; import servnow.servnow.common.code.UserInfoErrorCode; import servnow.servnow.common.exception.BadRequestException; @@ -20,7 +17,6 @@ import servnow.servnow.domain.user.repository.UserInfoRepository; import servnow.servnow.domain.user.repository.UserRepository; -import java.time.LocalDateTime; import java.util.UUID; @Service @@ -32,7 +28,7 @@ public class UserCommandService { private final UserInfoFinder userInfoFinder; private final UuidRepository uuidRepository; private final S3Manager s3Manager; - + private final PasswordEncoder passwordEncoder; public void profileSave(final Long userId, SaveEditProfilePageRequest request) { User user = userRepository.findById(userId) @@ -44,13 +40,13 @@ public void profileSave(final Long userId, SaveEditProfilePageRequest request) { String reconfirmPassword = request.reconfirmPassword() != null ? request.reconfirmPassword().trim() : ""; // 비밀번호 변경 로직 - if (!password.isEmpty()) { - if (password.equals(reconfirmPassword)) { - // 일반 로그인에서 사용할 암호화를 추후 적용할 예정 - user.setPassword(password); - } else { + if (password != null && !password.isBlank()) { + if (!password.equals(reconfirmPassword)) { throw new BadRequestException(UserErrorCode.WRONG_PASSWORD); } + + String encryptedPassword = passwordEncoder.encode(password); + user.setPassword(encryptedPassword); } // 프로필과 Serial ID는 항상 업데이트 가능 @@ -58,34 +54,31 @@ public void profileSave(final Long userId, SaveEditProfilePageRequest request) { if (userInfoFinder.isEmailDuplicate(request.serialId())) { throw new BadRequestException(UserErrorCode.DUPLICATE_SERIAL_ID); } + + // 프로필 업데이트 userInfo.setNickname(request.nickname()); user.setSerialId(request.serialId()); userRepository.save(user); userInfoRepository.save(userInfo); - // 이메일 변경 시 인증번호 확인 + + // 이메일 변경 로직 if (request.email() != null && !request.email().isEmpty()) { - if (request.certificationNumber() == null || !request.certificationNumber().equalsIgnoreCase(EmailService.ePw)) { - System.out.println("Stored Certification Number: " + EmailService.ePw); - System.out.println("Received Certification Number: " + request.certificationNumber()); - throw new BadRequestException(UserErrorCode.CERTIFICATION_NUMBER_MISMATCH); - } - // 인증이 성공했으므로 이메일 업데이트 userInfo.setEmail(request.email()); userInfoRepository.save(userInfo); } } public void updateProfile(MultipartFile file, Long userId) { - String url = null; - if (file != null && !file.isEmpty()) { - String uuid = UUID.randomUUID().toString(); - Uuid savedUuid = uuidRepository.save(Uuid.builder() - .uuid(uuid).build()); + String url = null; + if (file != null && !file.isEmpty()) { + String uuid = UUID.randomUUID().toString(); + Uuid savedUuid = uuidRepository.save(Uuid.builder() + .uuid(uuid).build()); - url = s3Manager.uploadFile(s3Manager.generateImage(savedUuid), file); - UserInfo userInfo = userInfoRepository.findByUserId(userId).orElseThrow(() -> new NotFoundException(UserInfoErrorCode.USER_INFO_NOT_FOUND)); - userInfo.setProfile_url(url); - userInfoRepository.save(userInfo); - } + url = s3Manager.uploadFile(s3Manager.generateImage(savedUuid), file); + UserInfo userInfo = userInfoRepository.findByUserId(userId).orElseThrow(() -> new NotFoundException(UserInfoErrorCode.USER_INFO_NOT_FOUND)); + userInfo.setProfile_url(url); + userInfoRepository.save(userInfo); + } } } \ No newline at end of file diff --git a/src/main/java/servnow/servnow/api/user/service/UserQueryService.java b/src/main/java/servnow/servnow/api/user/service/UserQueryService.java index b10e720..5e921a0 100644 --- a/src/main/java/servnow/servnow/api/user/service/UserQueryService.java +++ b/src/main/java/servnow/servnow/api/user/service/UserQueryService.java @@ -26,7 +26,7 @@ public class UserQueryService { private final UserInfoRepository userInfoRepository; private final UserRepository userRepository; private final UserInfoFinder userInfoFinder; - private final EmailService emailService; +// private final EmailService emailService; @Transactional(readOnly = true) public MyPageResponse getMyPage(final Long userId) { @@ -60,19 +60,6 @@ public boolean getSerialIdDuplicate(String serialId) { return userRepository.existsBySerialId(serialId); } - public ServnowResponse identityVerification(String email) throws Exception { - if (emailDuplicate(email)) { - return ServnowResponse.fail(UserErrorCode.EMAIL_DUPLICATE); - } - String confirm = emailService.sendSimpleMessage(email); - - if (confirm.isEmpty()) { - return ServnowResponse.fail(UserErrorCode.SEND_CERTIFICATION_NUMBER); - } else { - return ServnowResponse.success(CommonSuccessCode.OK); - } - } - @Transactional(readOnly = true) public UserPointGetResponse getUserPoint(final long userId){ return UserPointGetResponse.of(userInfoFinder.findByUserId(userId)); diff --git a/src/main/java/servnow/servnow/common/code/UserErrorCode.java b/src/main/java/servnow/servnow/common/code/UserErrorCode.java index 3f17f4c..eefed3f 100644 --- a/src/main/java/servnow/servnow/common/code/UserErrorCode.java +++ b/src/main/java/servnow/servnow/common/code/UserErrorCode.java @@ -17,6 +17,7 @@ public enum UserErrorCode implements ErrorCode { SEND_CERTIFICATION_NUMBER(HttpStatus.BAD_REQUEST, "인증번호 전송을 실패하였습니다."), CERTIFICATION_NUMBER_MISMATCH(HttpStatus.UNAUTHORIZED, "인증번호가 일치하지 않습니다."), AUTHENTICATION_FAILED(HttpStatus.UNAUTHORIZED, "인증이 진행되지 않았습니다."), + CERTIFICATION_NUMBER_REQUIRED(HttpStatus.BAD_REQUEST, "인증번호가 없습니다.") ;