Skip to content

Commit

Permalink
feat: 회원가입 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
conagreen committed Feb 6, 2024
1 parent 46767a4 commit 46afb8e
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.pickax.status.page.server.dto.request.auth.EmailAuthVerifyRequestDto;
import com.pickax.status.page.server.service.AuthService;
import com.pickax.status.page.server.dto.request.auth.SignupRequestDto;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -32,6 +33,12 @@ public ResponseEntity<Void> verifyEmailAuthenticationCodeForSignup(@RequestBody
return new ResponseEntity<>(HttpStatus.OK);
}

@PostMapping("/signup")
public ResponseEntity<Void> signup(@RequestBody @Valid SignupRequestDto signupRequestDto) {
this.authService.signup(signupRequestDto);
return new ResponseEntity<>(HttpStatus.OK);
}

@PostMapping("/resign")
public ResponseEntity<Void> resign(@RequestBody @Valid UserResignRequestDto userResignRequestDto) {
authService.resign(userResignRequestDto);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
public enum Mail {
COMPONENT_STATUS_NOTIFICATION("MAIL_TITLE_OF_COMPONENT_STATUS_NOTIFICATION", "COMPONENT_STATUS_NOTIFICATION"),
SIGNUP_EMAIL_AUTHENTICATION_CODE("MAIL_TITLE_OF_SIGNUP_EMAIL_AUTHENTICATION_CODE", "SIGNUP_EMAIL_AUTHENTICATION_CODE"),
USER_RESIGN("MAIL_TITLE_OF_USER_RESIGN", "USER_RESIGN");
USER_RESIGN("MAIL_TITLE_OF_USER_RESIGN", "USER_RESIGN"),
USER_SIGNUP("MAIL_TITLE_OF_USER_SIGNUP", "USER_SIGNUP");

@Getter
private String subject;
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/com/pickax/status/page/server/domain/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,23 @@ public class User {
@Enumerated(EnumType.STRING)
private UserStatus status;

@Column(name = "sign_up_at", nullable = false)
private LocalDateTime signUpDate;
@Column(name = "signup_at", nullable = false)
private LocalDateTime signupDate;

@Column(name = "withdrawal_at")
private LocalDateTime withdrawalDate;

private User(String email, String password, UserStatus status, LocalDateTime signupDate) {
this.email = email;
this.password = password;
this.status = status;
this.signupDate = signupDate;
}

public static User create(String email, String encodedPassword) {
return new User(email, encodedPassword, UserStatus.JOIN, LocalDateTime.now());
}

public void delete() {
email = "";
password = "";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.pickax.status.page.server.dto.request.auth;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
public class SignupRequestDto {
@Email
@NotBlank(message = "email 은(는) 공백일 수 없습니다.")
private String email;

@NotBlank(message = "password 은(는) 공백일 수 없습니다.")
@Pattern(regexp = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[!#$%&?])[A-Za-z\\d!#$%&?]{8,16}$")
private String password;

@NotBlank(message = "code 은(는) 공백일 수 없습니다.")
private String code;

public SignupRequestDto(String email, String password, String code) {
this.email = email;
this.password = password;
this.code = code;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.util.List;

import com.pickax.status.page.server.dto.request.auth.SignupRequestDto;
import com.pickax.status.page.server.dto.request.auth.EmailAuthVerifyRequestDto;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.core.Authentication;
Expand Down Expand Up @@ -36,7 +37,6 @@

import java.time.LocalDateTime;
import lombok.extern.slf4j.Slf4j;
import java.util.Optional;

@Slf4j
@Service
Expand All @@ -55,18 +55,19 @@ public class AuthService {
@Transactional
public void sendEmailAuthenticationCodeForSignup(EmailAuthSendRequestDto emailAuthSendRequestDto) {
String requestEmail = emailAuthSendRequestDto.getEmail();
userRepository.getUser(requestEmail, UserStatus.JOIN).ifPresent(user -> {
throw new CustomException(ErrorCode.DUPLICATE_USER);
});

checkDuplicatedUser(requestEmail);
cleanAllEmailAuthenticationByEmail(requestEmail);

String code = RandomStringUtils.randomNumeric(6);

emailAuthenticationRepository.save(EmailAuthentication.create(requestEmail, code, LocalDateTime.now().plusMinutes(10)));
emailService.sendEmailAuthenticationCodeForSignup(requestEmail, code);
}

private void checkDuplicatedUser(String email) {
userRepository.getUser(email, UserStatus.JOIN).ifPresent(user -> {
throw new CustomException(ErrorCode.DUPLICATE_USER);
});
}

private void cleanAllEmailAuthenticationByEmail(String email) {
List<EmailAuthentication> emailAuthentications = emailAuthenticationRepository.findAllByEmail(email);
if (!emailAuthentications.isEmpty()) {
Expand Down Expand Up @@ -108,10 +109,14 @@ private void cancelSiteAndDeactivateComponents(Site site) {

@Transactional(readOnly = true)
public void verifyEmailAuthenticationCodeForSignup(EmailAuthVerifyRequestDto emailAuthVerifyRequestDto) {
EmailAuthentication emailAuthentication = emailAuthenticationRepository.findFirst1ByEmail(emailAuthVerifyRequestDto.getEmail())
verifyEmailAuthenticationCodeForSignup(emailAuthVerifyRequestDto.getEmail(), emailAuthVerifyRequestDto.getCode());
}

private void verifyEmailAuthenticationCodeForSignup(String email, String code) {
EmailAuthentication emailAuthentication = emailAuthenticationRepository.findFirst1ByEmail(email)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_AUTHENTICATION_CODE));

if (!emailAuthentication.verify(emailAuthVerifyRequestDto.getCode())) {
if (!emailAuthentication.verify(code)) {
throw new CustomException(ErrorCode.INVALID_AUTHENTICATION_CODE);
}

Expand All @@ -134,4 +139,15 @@ private void verifyPassword(String inputPassword, String password) {
throw new CustomException(ErrorCode.INVALID_PASSWORD);
}
}

@Transactional
public void signup(SignupRequestDto signupRequestDto) {
String email = signupRequestDto.getEmail();
checkDuplicatedUser(email);
verifyEmailAuthenticationCodeForSignup(email, signupRequestDto.getCode());
userRepository.save(User.create(email, passwordEncoder.encode(signupRequestDto.getPassword())));

emailService.sendSignupEmail(email);
cleanAllEmailAuthenticationByEmail(email);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,19 @@ private MailMessageContext createUserResignEmailContext(UserResignEvent userResi
.to(userResignEvent.email())
.build();
}

public void sendSignupEmail(String email) {
MailMessageContext messageContext = createSignupEmailContext(email);
emailSender.send(messageContext);
}

private MailMessageContext createSignupEmailContext(String email) {
Context context = new Context();
context.setVariable("receiverEmail", email);
return MailMessageContext.builder()
.context(context)
.mailType(Mail.USER_SIGNUP)
.to(email)
.build();
}
}
2 changes: 2 additions & 0 deletions src/main/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
MAIL_TITLE_OF_COMPONENT_STATUS_NOTIFICATION=[QUACK_RUN] 컴포넌트 상태 변경 알림입니다.
MAIL_TITLE_OF_SIGNUP_EMAIL_AUTHENTICATION_CODE=[QUACK_RUN] 회원 가입 인증 안내 메일입니다.
MAIL_TITLE_OF_USER_RESIGN=[QUACK_RUN] 회원 탈퇴 안내 메일입니다.
MAIL_TITLE_OF_USER_SIGNUP=[QUACK_RUN] 회원 가입 안내 메일입니다.

#MAILING TEMPLATE
COMPONENT_STATUS_NOTIFICATION=component_status_notification
SIGNUP_EMAIL_AUTHENTICATION_CODE=signup_email_authentication_code
USER_RESIGN=user_resign
USER_SIGNUP=user_signup

## 400 BAD_REQUEST
INVALID_INPUT_VALUE=Invalid input value
Expand Down
78 changes: 78 additions & 0 deletions src/main/resources/templates/user_signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="ko" dir="auto" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">

<head></head>

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no">
<meta name="x-apple-disable-message-reformatting">
<meta name="color-scheme" content="light dark">
<meta name="supported-color-schemes" content="light dark">

<!-- Change the title to the title of your email -->
<title>Quack run - User signup</title>

<!--link to Roboto Slab font from google -->
<link rel="preconnect" href="https://fonts.googleapis.com" media="screen">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin media="screen">


<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->




</head>

<body class="body" style="margin: 0;padding: 0;word-spacing: normal;">
<div role="article" aria-label="quack run alert" lang="ko" dir="auto" class="wrapper" style="font-size:medium; font-size:max(16px, 1rem); font-family: georgia, serif;background:#F1EDFF">
<div style="display: none;">Quack Run - 회원가입 알림
<!-- the below code adds spacing after the preheader text -->
&#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &#8199;&#847; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &shy; &nbsp;
</div>
<table role="presentation" width="100%" align="center" cellpadding="16" border="0" style="background:#F1EDFF; max-width: 600px; mso-padding-alt: 0; margin: 0 auto; padding: 60px 30px;">
<tr>
<td style="background:#ffffff">
<table style="margin:0 auto;background:#ffffff; padding:20px;overflow: auto;" class="container">
<tr>
<td>
<h1 style="margin: 1em 0;font-size: 2em; text-align:center;">
회원가입 알림</h1>
<br>
</td>
</tr>
<tr>
<td>
<p>안녕하세요, <span th:text="${receiverEmail}"></span></p>
<p>회원가입이 완료되었습니다.</p>
<p></p>
</td>

</tr>
<tr>
<td>
<div class="btn" style="font-size: 16px;font-weight: bold;margin: 0;padding: 12px 24px;background-color: #7480FF;text-align: center;cursor: pointer;">
<a href="" style="color: #ffffff">확인</a>
</div>
</td>
</tr>
</table>
</td>

</tr>
</table>
</div>
</body>

</html>
Loading

0 comments on commit 46afb8e

Please sign in to comment.