-
Notifications
You must be signed in to change notification settings - Fork 0
Fix/#39 - 소셜로그인 된 이메일로 회원가입 위한 인증코드 전송 API 호출 시 이메일 전송 X #44
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
Changes from 9 commits
a32114f
7c22bc0
0d48647
dfc06d4
5269def
eb28efb
63a5867
e074e26
62ec197
1ce5347
43e0edb
ba42c5c
6292674
2de0ce7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,12 @@ | ||
| package com.whereyouad.WhereYouAd.domains.user.application.dto.response; | ||
|
|
||
| import com.whereyouad.WhereYouAd.domains.user.domain.constant.Provider; | ||
|
|
||
| public record EmailSentResponse( | ||
| String message, //인증코드를 이메일로 전송했습니다. | ||
| String email, //전송한 이메일 | ||
| long expireIn //만료시간 (500L -> 500초) | ||
| Long expireIn, //만료시간 (500L -> 500초) | ||
| boolean isProviderLinked, | ||
| Provider providerType | ||
| ) { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.whereyouad.WhereYouAd.domains.user.application.dto.response; | ||
|
|
||
| public record PasswordResetResponse( | ||
| String message, //인증코드를 이메일로 전송했습니다. | ||
| String email, //전송한 이메일 | ||
| Long expireIn //만료시간 (500L -> 500초) | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,14 @@ | ||
| package com.whereyouad.WhereYouAd.domains.user.domain.service; | ||
|
|
||
| import com.whereyouad.WhereYouAd.domains.user.application.dto.response.EmailSentResponse; | ||
| import com.whereyouad.WhereYouAd.domains.user.application.dto.response.PasswordResetResponse; | ||
| import com.whereyouad.WhereYouAd.domains.user.application.mapper.UserConverter; | ||
| import com.whereyouad.WhereYouAd.domains.user.domain.constant.Provider; | ||
| import com.whereyouad.WhereYouAd.domains.user.exception.handler.UserHandler; | ||
| import com.whereyouad.WhereYouAd.domains.user.exception.code.UserErrorCode; | ||
| import com.whereyouad.WhereYouAd.domains.user.persistence.entity.AuthProviderAccount; | ||
| import com.whereyouad.WhereYouAd.domains.user.persistence.entity.User; | ||
| import com.whereyouad.WhereYouAd.domains.user.persistence.repository.AuthProviderAccountRepository; | ||
| import com.whereyouad.WhereYouAd.domains.user.persistence.repository.UserRepository; | ||
| import com.whereyouad.WhereYouAd.global.utils.RedisUtil; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
@@ -14,6 +20,8 @@ | |
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| @Transactional | ||
| @Service | ||
| @RequiredArgsConstructor | ||
|
|
@@ -23,6 +31,7 @@ public class EmailService { | |
| private final JavaMailSender emailSender; | ||
| private final RedisUtil redisUtil; | ||
| private final UserRepository userRepository; | ||
| private final AuthProviderAccountRepository authProviderAccountRepository; | ||
|
|
||
| // application.yml 적용 필요 | ||
| @Value("${spring.mail.username}") | ||
|
|
@@ -34,19 +43,36 @@ public class EmailService { | |
| // 인증코드 이메일 발송 로직 (최초 회원가입 시) | ||
| public EmailSentResponse sendEmail(String toEmail) { | ||
| if (userRepository.existsByEmail(toEmail)) { // 이미 해당 이메일로 생성한 계정이 있으면 | ||
| throw new UserHandler(UserErrorCode.USER_EMAIL_DUPLICATE); // 이메일 중복 예외(회원가입 시 사용했던 예외) | ||
| //해당 사용자 정보 조회 | ||
| User user = userRepository.findUserByEmail(toEmail) | ||
| .orElseThrow(() -> new UserHandler(UserErrorCode.USER_NOT_FOUND)); | ||
|
|
||
| //해당 사용자에 연관된 AuthProviderAccount 조회 | ||
| Optional<AuthProviderAccount> authProviderAccount = authProviderAccountRepository.findByUser(user); | ||
|
|
||
| //만약 AuthProviderAccount 가 없으면 | ||
| if (authProviderAccount.isEmpty()) { | ||
| //단순 이메일 회원가입에서 이메일 값이 중복인 것이므로 예외(기존 예외처리 로직) | ||
| throw new UserHandler(UserErrorCode.USER_EMAIL_DUPLICATE); | ||
| } else { //만약 AuthProviderAccount 가 있으면 | ||
| //해당 소셜 로그인 플랫폼 타입을 추출해서 반환 | ||
| Provider provider = authProviderAccount.get().getProvider(); | ||
|
|
||
| return UserConverter.toEmailSentResponseFail(toEmail, provider); | ||
| } | ||
| } | ||
|
Comment on lines
44
to
63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 불필요한 DB 쿼리 중복: Line 45에서
♻️ 쿼리 최적화 제안 public EmailSentResponse sendEmail(String toEmail) {
- if (userRepository.existsByEmail(toEmail)) {
- User user = userRepository.findUserByEmail(toEmail)
- .orElseThrow(() -> new UserHandler(UserErrorCode.USER_NOT_FOUND));
+ Optional<User> existingUser = userRepository.findUserByEmail(toEmail);
+ if (existingUser.isPresent()) {
+ User user = existingUser.get();
Optional<AuthProviderAccount> authProviderAccount = authProviderAccountRepository.findByUser(user);As per coding guidelines, "JPA 사용 시 N+1 문제나 불필요한 쿼리가 발생하지 않는지 ... 체크하라." 🤖 Prompt for AI Agents |
||
|
|
||
| //해당 이메일로 이미 생성된 계정 없으면 이메일 전송 진행 | ||
| String type = "회원가입"; | ||
|
|
||
| return emailSendTemplate(toEmail, type); | ||
| //템플릿 호출 | ||
| return (EmailSentResponse) emailSendTemplate(toEmail, type); | ||
| } | ||
|
|
||
| // 비밀번호 재설정을 위한 인증코드 이메일 발송 로직 (이미 회원가입 된 상태에서 비밀번호 재설정) | ||
| public EmailSentResponse sendEmailForPwd(String toEmail) { | ||
| public PasswordResetResponse sendEmailForPwd(String toEmail) { | ||
| if (userRepository.existsByEmail(toEmail)) { // 이미 회원가입 되어있는 것이 확인되면 | ||
| String type = "비밀번호 재설정"; | ||
| return emailSendTemplate(toEmail, type); // 정상적으로 이메일 발송 | ||
| return (PasswordResetResponse) emailSendTemplate(toEmail, type); // 정상적으로 이메일 발송 | ||
| } else { // 만약 회원가입 되어있지 않다면 | ||
| throw new UserHandler(UserErrorCode.USER_NOT_FOUND); // 예외발생 | ||
| } | ||
|
|
@@ -69,8 +95,9 @@ public void sendEmailForOrgInvitation(String token, String toEmail, String orgNa | |
| } | ||
| } | ||
|
|
||
| // 기존 이메일 발송 로직 템플릿 화 | ||
| private EmailSentResponse emailSendTemplate(String toEmail, String type) { | ||
| //기존 이메일 발송 로직 템플릿 화 | ||
| //"회원가입 시 인증 이메일 발송" 과 "비밀번호 재설정 시 인증 이메일 발송" 에 대한 Response 분리 위해 반환값 Object로 변경 (fix/#39) | ||
| private Object emailSendTemplate(String toEmail, String type) { | ||
ojy0903 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // 인증코드 재전송 로직 -> 이미 Redis 에 해당 이메일 인증코드가 있을시 삭제 | ||
| String redisKey = "CODE:" + toEmail; | ||
|
|
@@ -111,7 +138,13 @@ private EmailSentResponse emailSendTemplate(String toEmail, String type) { | |
| // 테스트 계정의 인증은 서버 로그를 통해 인증코드를 얻어 입력. | ||
| redisUtil.setDataExpire("CODE:" + toEmail, authCode, 60 * 3L); | ||
|
|
||
| return new EmailSentResponse("인증코드를 이메일로 전송했습니다.", toEmail, 180L); | ||
| if (type.equals("회원가입")) { //해당 템플릿 메서드를 "회원가입을 위한 이메일 인증" 에서 호출한 경우, | ||
| //해당 DTO 형식에 맞춰 반환 | ||
| return UserConverter.toEmailSentResponseSuccess(toEmail); | ||
| } else { //"비밀번호 재설정" 에서 호출한 경우, | ||
| //해당 DTO 형식에 맞춰 반환 | ||
| return UserConverter.toPasswordResetResponse(toEmail); | ||
| } | ||
| } | ||
|
|
||
| // 인증코드 검증 메서드 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,16 @@ | ||
| package com.whereyouad.WhereYouAd.domains.user.persistence.repository; | ||
|
|
||
| import com.whereyouad.WhereYouAd.domains.user.persistence.entity.AuthProviderAccount; | ||
| import com.whereyouad.WhereYouAd.domains.user.persistence.entity.User; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.data.jpa.repository.Query; | ||
| import org.springframework.data.repository.query.Param; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| public interface AuthProviderAccountRepository extends JpaRepository<AuthProviderAccount, Long> { | ||
| AuthProviderAccount findByProviderId(String username); | ||
|
|
||
| @Query("select apa from AuthProviderAccount apa where apa.user = :user") | ||
| Optional<AuthProviderAccount> findByUser(@Param(value = "user") User user); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.