-
Notifications
You must be signed in to change notification settings - Fork 0
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
[임시 비밀번호 발급 및 전송] 임시 비밀번호 발급 및 전송 비즈니스 로직/API 구성(#35) #40
Changes from 47 commits
d8cc31d
9b49093
e953b85
7a7b7c3
d781de3
8aad1e4
7dd07aa
3a6137d
9a4cae0
52995c4
a2c164d
d6ce69e
6c7ff1d
01f3138
95c99d8
672f7bb
f25c26f
4d26a15
7efedf9
d77dae4
d0bbec9
fa4204d
87ec03e
e6f7eb1
4aba46d
6cc2cb6
1d75218
4e54bfd
ba20da8
0d4b90f
78ac728
5bd4d1f
bdc8259
f6e4e06
811198d
25703a7
a798b4c
1bfde17
89c4db5
7216f5d
52373f1
3cd825f
50b9982
45adb7a
d50b731
d514a96
78b6f1d
76d2eb1
caeea54
0905fdb
bb589e0
8708095
2d78b00
947115a
be5153e
7ea89d0
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 |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package yeonba.be.config; | ||
|
||
import java.util.Properties; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.mail.javamail.JavaMailSender; | ||
import org.springframework.mail.javamail.JavaMailSenderImpl; | ||
|
||
@Configuration | ||
public class MailConfig { | ||
|
||
@Value("${spring.mail.host}") | ||
private String serverHost; | ||
|
||
@Value("${spring.mail.port}") | ||
private int serverPort; | ||
|
||
@Value("${spring.mail.username}") | ||
private String username; | ||
|
||
@Value("${spring.mail.password}") | ||
private String password; | ||
|
||
@Bean | ||
public JavaMailSender javaMailSender() { | ||
JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); | ||
mailSender.setHost(serverHost); | ||
mailSender.setPort(serverPort); | ||
mailSender.setUsername(username); | ||
mailSender.setPassword(password); | ||
|
||
Properties properties = mailSender.getJavaMailProperties(); | ||
properties.put("mail.transport.protocol", "smtp"); | ||
properties.put("mail.smtp.auth", "true"); | ||
properties.put("mail.smtp.starttls.enable", "true"); | ||
|
||
return mailSender; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -3,6 +3,8 @@ | |||||||
import io.swagger.v3.oas.annotations.Operation; | ||||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||||||||
import io.swagger.v3.oas.annotations.tags.Tag; | ||||||||
import jakarta.validation.Valid; | ||||||||
import lombok.RequiredArgsConstructor; | ||||||||
import org.springframework.http.ResponseEntity; | ||||||||
import org.springframework.web.bind.annotation.PostMapping; | ||||||||
import org.springframework.web.bind.annotation.RequestBody; | ||||||||
|
@@ -17,12 +19,16 @@ | |||||||
import yeonba.be.login.dto.response.UserJoinResponse; | ||||||||
import yeonba.be.login.dto.response.UserLoginResponse; | ||||||||
import yeonba.be.login.dto.response.UserRefreshTokenResponse; | ||||||||
import yeonba.be.login.service.LoginService; | ||||||||
import yeonba.be.util.CustomResponse; | ||||||||
|
||||||||
@Tag(name = "Login", description = "로그인 관련 API") | ||||||||
@RestController | ||||||||
@RequiredArgsConstructor | ||||||||
public class LoginController { | ||||||||
|
||||||||
private final LoginService loginService; | ||||||||
|
||||||||
@Operation(summary = "회원가입", description = "회원가입을 할 수 있습니다.") | ||||||||
@PostMapping("/users/join") | ||||||||
public ResponseEntity<CustomResponse<UserJoinResponse>> join( | ||||||||
|
@@ -69,17 +75,13 @@ public ResponseEntity<CustomResponse<UserIdInquiryResponse>> idInquiry( | |||||||
.body(new CustomResponse<>(new UserIdInquiryResponse("[email protected]"))); | ||||||||
} | ||||||||
|
||||||||
@Operation( | ||||||||
summary = "비밀번호 찾기", | ||||||||
description = "이메일로 임시 비밀번호를 발급받을 수 있습니다." | ||||||||
) | ||||||||
@ApiResponse( | ||||||||
responseCode = "204", | ||||||||
description = "임시 비밀번호 발급(비밀번호 찾기) 정상 처리" | ||||||||
) | ||||||||
@Operation(summary = "비밀번호 찾기", description = "이메일로 임시 비밀번호를 발급받을 수 있습니다.") | ||||||||
@ApiResponse(responseCode = "202", description = "임시 비밀번호 발급(비밀번호 찾기) 정상 처리") | ||||||||
@PostMapping("/users/help/pw-inquiry") | ||||||||
public ResponseEntity<CustomResponse<Void>> passwordInquiry( | ||||||||
@RequestBody UserPasswordInquiryRequest request) { | ||||||||
@RequestBody @Valid UserPasswordInquiryRequest request) { | ||||||||
|
||||||||
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. 제가 생각할 때는
Suggested change
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. 로직 흐름상 더 자연스러운 것 같습니다. 반영하겠습니다! |
||||||||
loginService.sendTemporaryPasswordMail(request); | ||||||||
|
||||||||
return ResponseEntity | ||||||||
.accepted() | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,19 @@ | ||
package yeonba.be.login.dto.request; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.AllArgsConstructor; | ||
import jakarta.validation.constraints.Pattern; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
public class UserPasswordInquiryRequest { | ||
|
||
@Schema( | ||
type = "string", | ||
@Schema(type = "string", | ||
description = "임시 비밀번호를 받을 이메일", | ||
example = "[email protected]" | ||
) | ||
example = "[email protected]") | ||
@Pattern( | ||
regexp = "[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$", | ||
message = "유효하지 않은 이메일 형식입니다.") | ||
private String email; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package yeonba.be.login.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import yeonba.be.login.dto.request.UserPasswordInquiryRequest; | ||
import yeonba.be.user.entity.User; | ||
import yeonba.be.user.repository.UserQuery; | ||
import yeonba.be.util.EmailService; | ||
import yeonba.be.util.TemporaryPasswordGenerator; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class LoginService { | ||
|
||
private final String TEMPORARY_PASSWORD_EMAIL_SUBJECT = "연바(연애는 바로 지금) 임시비밀번호 발급"; | ||
private final String TEMPORARY_PASSWORD_EMAIL_TEXT = "임시비밀번호 : %s"; | ||
private final UserQuery userQuery; | ||
private final EmailService emailService; | ||
|
||
/* | ||
임시 비밀번호는 다음 과정을 거친다. | ||
1. 요청 이메일 기반 사용자 조회 | ||
2. 임시 비밀번호 생성 | ||
3. 사용자 비밀번호, 임시 비밀번호로 변경 | ||
4. 임시 비밀번호 발급 메일 전송 | ||
*/ | ||
Comment on lines
+21
to
+27
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. ? |
||
|
||
// TODO : 비밀번호 암호화 로직 추가 | ||
|
||
@Transactional | ||
public void sendTemporaryPasswordMail(UserPasswordInquiryRequest request) { | ||
|
||
String email = request.getEmail(); | ||
User user = userQuery.findByEmail(email); | ||
|
||
String temporaryPassword = TemporaryPasswordGenerator.generatePassword(); | ||
|
||
String encryptedPassword = temporaryPassword; | ||
user.changePassword(encryptedPassword); | ||
|
||
String text = String.format(TEMPORARY_PASSWORD_EMAIL_TEXT, temporaryPassword); | ||
emailService.sendMail(email, TEMPORARY_PASSWORD_EMAIL_SUBJECT, text); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,7 @@ | |
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.Size; | ||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
@@ -17,109 +15,82 @@ public class UserProfileDetailResponse { | |
|
||
@Schema( | ||
type = "array", | ||
description = "프로필 이미지" | ||
) | ||
@Size(min = 3, max = 3) | ||
description = "프로필 이미지") | ||
private List<String> profilePhotoUrls; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "성별", | ||
example = "남" | ||
) | ||
example = "남") | ||
private String gender; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "이름", | ||
example = "안민재" | ||
) | ||
example = "안민재") | ||
private String name; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "생년월일", | ||
example = "1998-01-01" | ||
) | ||
example = "1998-01-01") | ||
@JsonFormat(pattern = "yyyy-MM-dd") | ||
private LocalDate birth; | ||
|
||
@Schema( | ||
type = "number", | ||
description = "키", | ||
example = "181" | ||
) | ||
example = "181") | ||
private int height; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "이메일", | ||
example = "[email protected]" | ||
) | ||
example = "[email protected]") | ||
private String email; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "전화번호", | ||
example = "01011112222" | ||
) | ||
example = "01011112222") | ||
private String phoneNumber; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "별명", | ||
example = "존잘남" | ||
) | ||
example = "존잘남") | ||
private String nickname; | ||
|
||
@Schema( | ||
type = "number", | ||
description = "사진 싱크로율", | ||
example = "80" | ||
) | ||
private int photoSyncRate; | ||
example = "80") | ||
private double photoSyncRate; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "체형", | ||
example = "메른 체형" | ||
) | ||
example = "메른 체형") | ||
private String bodyType; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "직업", | ||
example = "학생" | ||
) | ||
example = "학생") | ||
private String job; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "음주 성향", | ||
example = "자주" | ||
) | ||
private String drinkingHabit; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "흡연 성향", | ||
example = "가끔" | ||
) | ||
private String smokingHabit; | ||
|
||
@Schema( | ||
type = "string", | ||
description = "MBTI", | ||
example = "ISTP" | ||
) | ||
example = "ISTP") | ||
private String mbti; | ||
|
||
public UserProfileDetailResponse(User user) { | ||
|
||
this.profilePhotoUrls = user.getProfilePhotos().stream() | ||
.map(ProfilePhoto::getPhotoUrl) | ||
.toList(); | ||
this.gender = user.isGender() ? "남" : "여"; | ||
this.gender = user.getGender(); | ||
this.name = user.getName(); | ||
this.birth = user.getBirth(); | ||
this.height = user.getHeight(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.