Skip to content
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

Merged
merged 56 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d8cc31d
feat: 화살 보내기 요청 DTO 추가(#24)
Minjae-An Mar 9, 2024
9b49093
feat: 확살 송수신 내역 repository, 내역 확인 로직 추가(#24)
Minjae-An Mar 9, 2024
e953b85
feat: 화살 송수신 내역 존재 여부 확인 로직 추가(#24)
Minjae-An Mar 9, 2024
7a7b7c3
feat: 화살 송수신 내역 저장 기능 구현(#24)
Minjae-An Mar 9, 2024
d781de3
feat: 화살 관련 예외 enum 정의(#24)
Minjae-An Mar 9, 2024
8aad1e4
feat: 사용자 화살 감소 로직 추가(#24)
Minjae-An Mar 9, 2024
7dd07aa
refactor: 생성 시간 필드, 불필요한 업데이트 불가 DDL 속성 삭제(#24)
Minjae-An Mar 9, 2024
3a6137d
feat: 화살 보내기 비즈니스 로직 추가(#24)
Minjae-An Mar 9, 2024
9a4cae0
feat: 화살 보내기 API 구현(#24)
Minjae-An Mar 9, 2024
52995c4
refactor: 화살 command repository 삭제(#24)
Minjae-An Mar 9, 2024
a2c164d
refactor: 코드 정렬 수정(#24)
Minjae-An Mar 9, 2024
d6ce69e
Merge branch 'dev' into feat/#24-send-arrow
Minjae-An Mar 11, 2024
6c7ff1d
refactor: 사용자 화살 증감 메서드 이름 수정(#24)
Minjae-An Mar 11, 2024
01f3138
feat: 화살 관련 예외 enum 추가(#24)
Minjae-An Mar 11, 2024
95c99d8
refactor: 화살 내역 존재 여부 확인 메서드 이름 수정(#24)
Minjae-An Mar 11, 2024
672f7bb
refactor: 코드 배치 수정(#24)
Minjae-An Mar 11, 2024
f25c26f
refactor: 화살 보내기 API 파라미터 이름 수정(#24)
Minjae-An Mar 11, 2024
4d26a15
refactor: 컨벤션에 맞게 코드 배치 수정(#24)
Minjae-An Mar 11, 2024
7efedf9
feat: 이름 칼럼, 생성자 추가(#27)
Minjae-An Mar 11, 2024
d77dae4
feat: 상대 프로필 응답 DTO 수정(#27)
Minjae-An Mar 11, 2024
d0bbec9
feat: 사용자 엔티티 수정(#27)
Minjae-An Mar 11, 2024
fa4204d
feat: 상대 프로필 조회 비즈니스 로직 추가(#27)
Minjae-An Mar 11, 2024
87ec03e
feat: 상대 프로필 API 구현 및 코드 정렬(#27)
Minjae-An Mar 11, 2024
e6f7eb1
feat: 사용자 엔티티 수정(#27)
Minjae-An Mar 13, 2024
4aba46d
feat: 사용자 프로필 응답 DTO 수정(#27)
Minjae-An Mar 13, 2024
6cc2cb6
feat: 사용자 프로필 상세 응답 DTO 수정(#27)
Minjae-An Mar 13, 2024
1d75218
feat: 사용자 프로필 조회 비즈니스 로직 수정(#27)
Minjae-An Mar 13, 2024
4e54bfd
chore: spring mail 종속성 추가(#35)
Minjae-An Mar 13, 2024
ba20da8
chore: Gmail SMTP 사용을 위한 설정 추가(#35)
Minjae-An Mar 13, 2024
0d4b90f
feat: 이메일 기반 사용자 조회 로직 추가(#35)
Minjae-An Mar 13, 2024
78ac728
feat: 이메일 기반 사용자 조회 로직 추가(#35)
Minjae-An Mar 13, 2024
5bd4d1f
feat: 서비스 사용 정규식 enum 정의(#35)
Minjae-An Mar 13, 2024
bdc8259
feat: 임시 비밀번호 발급 기능 구현(#35)
Minjae-An Mar 13, 2024
f6e4e06
feat: 메일 관련 설정 정의(#35)
Minjae-An Mar 13, 2024
811198d
feat: 이메일 전송 로직 추가(#35)
Minjae-An Mar 13, 2024
25703a7
feat: 임시 비밀번호 발급 비즈니스 로직 추가(#35)
Minjae-An Mar 13, 2024
a798b4c
feat: 임시 비밃번호 발급 비즈니스 로직 트랜잭션 정의 추가(#35)
Minjae-An Mar 13, 2024
1bfde17
feat: 임시 비밀번호 발급 요청 DTO 수정(#35)
Minjae-An Mar 13, 2024
89c4db5
feat: 임시 비밀번호 발급 API 구현(#35)
Minjae-An Mar 13, 2024
7216f5d
Merge branch 'dev' into feat/#35-send-temporary-password
Minjae-An Mar 13, 2024
52373f1
Merge branch 'dev' into feat/#35-send-temporary-password
Minjae-An Mar 14, 2024
3cd825f
Merge branch 'dev' into feat/#35-send-temporary-password
Minjae-An Mar 14, 2024
50b9982
refactor: 병합에 따른 코드 재배치(#35)
Minjae-An Mar 14, 2024
45adb7a
refactor: 병합에 따른 코드 재배치(#35)
Minjae-An Mar 14, 2024
d50b731
feat: 임시 비밀번호 생성 로직 변경(#35)
Minjae-An Mar 15, 2024
d514a96
chore: application.yml 메일 관련 속성 수정(#35)
Minjae-An Mar 15, 2024
78b6f1d
feat: 비밀번호 찾기 API, 이메일 형식 검증 추가(#35)
Minjae-An Mar 17, 2024
76d2eb1
Merge branch 'dev' into feat/#35-send-temporary-password
Minjae-An Mar 18, 2024
caeea54
refactor: 클래스 이름 수정(#35)
Minjae-An Mar 18, 2024
0905fdb
chore: application.yml 내용 정렬(#35)
Minjae-An Mar 18, 2024
bb589e0
refactor: 외부 설정 필드 주입 형태 수정(#35)
Minjae-An Mar 18, 2024
8708095
refactor: 외부 설정 필드 주입 형태 수정(#35)
Minjae-An Mar 18, 2024
2d78b00
refactor: 파라미터 어노테이션 순서 수정(#35)
Minjae-An Mar 18, 2024
947115a
refactor: 잘못된 들여쓰기 수정을 위한 코드 정렬(#8)
Minjae-An Mar 21, 2024
be5153e
refactor: 불필요한 spring-mail 관련 설정 삭제(#8)
Minjae-An Mar 21, 2024
7ea89d0
refactor: 잘못된 들여쓰기 수정, 코드 정렬(#35)
Minjae-An Mar 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions be/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ dependencies {
// aws s3
implementation 'software.amazon.awssdk:aws-sdk-java:2.16.83'
implementation 'software.amazon.awssdk:s3:2.16.83'

// spring mail
implementation 'org.springframework.boot:spring-boot-starter-mail:3.2.2'
}

tasks.named('bootBuildImage') {
Expand Down
40 changes: 40 additions & 0 deletions be/src/main/java/yeonba/be/config/MailConfig.java
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@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;
@Value("${GOOGLE_SMTP_HOST}")
private String serverHost;
@Value("${GOOGLE_SMTP_PORT}")
private int serverPort;
@Value("${GOOGLE_SMTP_USERNAME}")
private String username;
@Value("${GOOGLE_SMTP_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;
}
}
20 changes: 11 additions & 9 deletions be/src/main/java/yeonba/be/login/controller/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(
Expand Down Expand Up @@ -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) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 생각할 때는 @RequestBody UserPasswordInquiryRequest를 하나로 보고 이것을 @Valid로 검증한다라는 의미로 생각하는게 자연스러운데 어떻게 생각하시나요?

Suggested change
@RequestBody @Valid UserPasswordInquiryRequest request) {
@Valid @RequestBody UserPasswordInquiryRequest request) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로직 흐름상 더 자연스러운 것 같습니다. 반영하겠습니다!

loginService.sendTemporaryPasswordMail(request);

return ResponseEntity
.accepted()
Expand Down
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;
}
45 changes: 45 additions & 0 deletions be/src/main/java/yeonba/be/login/service/LoginService.java
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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
32 changes: 10 additions & 22 deletions be/src/main/java/yeonba/be/user/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import yeonba.be.user.dto.response.UserQueryPageResponse;
import yeonba.be.user.service.BlockService;
import yeonba.be.user.service.FavoriteService;
import yeonba.be.user.service.UserService;
import yeonba.be.util.CustomResponse;

@Tag(name = "User", description = "사용자 API")
Expand All @@ -29,8 +30,9 @@
public class UserController {

private final BlockService blockService;
private final ReportService reportService;
private final FavoriteService favoriteService;
private final ReportService reportService;
private final UserService userService;

@Operation(
summary = "이성(다른 사용자) 목록 조회",
Expand All @@ -50,33 +52,19 @@ public ResponseEntity<CustomResponse<UserQueryPageResponse>> users(
}


@Operation(
summary = "다른 사용자 프로필 조회",
description = "다른 사용자의 프로필을 조회할 수 있습니다."
)
@ApiResponse(
responseCode = "200",
description = "사용자 프로필 정상 조회"
)
@Operation(summary = "다른 사용자 프로필 조회", description = "다른 사용자의 프로필을 조회할 수 있습니다.")
@ApiResponse(responseCode = "200", description = "사용자 프로필 정상 조회")
@GetMapping("/users/{userId}")
public ResponseEntity<CustomResponse<UserProfileResponse>> profile(
@RequestAttribute("userId") long userId,
@Parameter(description = "조회대상 사용자 ID", example = "1")
@PathVariable long userId) {
@PathVariable("userId") long targetUserId) {

UserProfileResponse response = userService.getTargetUserProfile(userId, targetUserId);

return ResponseEntity
.ok()
.body(new CustomResponse<>(
new UserProfileResponse(
"존잘남",
23,
177,
"서울시 강남구",
80,
"저음",
"여우상",
false
)
));
.body(new CustomResponse<>(response));
}

@Operation(summary = "즐겨찾기 등록", description = "다른 사용자를 자신의 즐겨찾기에 등록할 수 있습니다.")
Expand Down
Loading