Skip to content

Commit

Permalink
[JT-28] 회원가입 기능 PR입니다.
Browse files Browse the repository at this point in the history
[JT-28] 회원가입 기능 PR입니다.
  • Loading branch information
ymkim97 authored Sep 4, 2023
2 parents c633683 + 4e108f5 commit d0a50a5
Show file tree
Hide file tree
Showing 21 changed files with 278 additions and 78 deletions.
15 changes: 13 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ subprojects {

project(':module-application') {
dependencies {
implementation project(':module-core')
implementation project(':module-domain')
implementation project(':module-domain-s3')
implementation project(':module-domain')
implementation project(':module-domain-smtp')
implementation project(':module-core')
}
}

Expand All @@ -52,6 +52,8 @@ project(':module-domain') {

dependencies {
implementation project(':module-core')
implementation project(':module-domain-smtp')
implementation project(':module-internal')
}
}

Expand All @@ -63,6 +65,15 @@ project(':module-domain-s3') {
}
}

project(':module-domain-smtp') {
bootJar.enabled = false

dependencies {
implementation project(':module-core')
implementation project(':module-internal')
}
}

project(':module-internal') {
bootJar.enabled = false

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.devtoon.jtoon.member.presentation;

import com.devtoon.jtoon.member.application.MemberService;
import com.devtoon.jtoon.member.request.SignUpDto;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.devtoon.jtoon.member.application.MemberService;
import com.devtoon.jtoon.member.request.SignUpDto;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/members")
Expand All @@ -19,10 +22,13 @@ public class MemberController {
private final MemberService memberService;

@PostMapping
public ResponseEntity<Void> signUp(@RequestBody @Valid SignUpDto signUpDto) {
@ResponseStatus(HttpStatus.CREATED)
public void signUp(@RequestBody @Valid SignUpDto signUpDto) {
memberService.createMember(signUpDto);

return new ResponseEntity<>(HttpStatus.CREATED);
}

@GetMapping("/email-authorization")
public String authenticateEmail(@RequestParam(value = "email") String email) {
return memberService.sendEmailAuthentication(email);
}
}
2 changes: 1 addition & 1 deletion module-application/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
spring:
profiles:
include: s3
include: s3, smtp
4 changes: 4 additions & 0 deletions module-domain-smtp/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
// SMTP
implementation 'org.springframework.boot:spring-boot-starter-mail'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.devtoon.jtoon.smtp.application;

import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.devtoon.jtoon.exception.ExceptionCode;
import com.devtoon.jtoon.exception.MemberException;
import com.devtoon.jtoon.smtp.entity.Mail;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class SmtpService {

private final JavaMailSender javaMailSender;

public void sendMail(Mail mail) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();

try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "utf-8");
mimeMessageHelper.setTo(mail.getTo());
mimeMessageHelper.setSubject(mail.getSubject());
mimeMessageHelper.setText(mail.getText());
javaMailSender.send(mimeMessage);
} catch (MessagingException | MailException e) {
throw new MemberException(ExceptionCode.MEMBER_MESSAGE_SEND_FAILED);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.devtoon.jtoon.smtp.config;

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;

import java.util.Properties;

@Configuration
public class MailConfig {

@Value("${smtp.username}")
private String username;

@Value("${smtp.password}")
private String password;

@Value("${smtp.host}")
private String host;

@Value("${smtp.port}")
private Integer port;

@Bean
public JavaMailSender javaMailSender() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
javaMailSender.setUsername(username);
javaMailSender.setPassword(password);
javaMailSender.setPort(port);
javaMailSender.setJavaMailProperties(getMailProperties());

return javaMailSender;
}

private Properties getMailProperties() {
Properties properties = new Properties();
properties.setProperty("mail.transport.protocol", "smtp");
properties.setProperty("mail.smtp.auth", "true");
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.debug", "true");
properties.setProperty("mail.smtp.ssl.trust","smtp.google.com");
properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");

return properties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.devtoon.jtoon.smtp.entity;

import lombok.Builder;
import lombok.Getter;

@Getter
public class Mail {

private static final String DEFAULT_SUBJECT = "[JTOON] 이메일 관련 인증입니다.";

private String subject = DEFAULT_SUBJECT;
private String to;
private String text;

@Builder
private Mail(String subject, String to, String text) {
this.subject = subject;
this.to = to;
this.text = text;
}

public static Mail createEvent(String subject, String to, String text) {
return Mail.builder()
.subject(subject)
.to(to)
.text(text)
.build();
}

public static Mail createAuthentication(String to, String text) {
return Mail.builder()
.to(to)
.text(text)
.build();
}
}
5 changes: 4 additions & 1 deletion module-domain/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ repositories {
dependencies {
// JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation project(path: ':module-internal')
implementation project(path: ':module-domain-smtp')

// I-AM-PORT
implementation 'com.github.iamport:iamport-rest-client-java:0.2.23'
Expand All @@ -21,4 +21,7 @@ dependencies {

// Bean Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,53 @@
package com.devtoon.jtoon.member.application;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.devtoon.jtoon.exception.ExceptionCode;
import com.devtoon.jtoon.exception.MemberException;
import com.devtoon.jtoon.member.entity.Member;
import com.devtoon.jtoon.member.repository.MemberRepository;
import com.devtoon.jtoon.member.request.SignUpDto;
import com.devtoon.jtoon.smtp.application.SmtpService;
import com.devtoon.jtoon.smtp.entity.Mail;
import java.util.UUID;
import lombok.RequiredArgsConstructor;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {

private final SmtpService smtpService;
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;

@Transactional
public void createMember(SignUpDto signUpDto) {
Member member = signUpDto.toEntity();
validateDuplicateEmail(signUpDto.email());
String encryptedPassword = encodePassword(signUpDto.password());
Member member = signUpDto.toEntity(encryptedPassword);
memberRepository.save(member);
}

public String sendEmailAuthentication(String email) {
validateDuplicateEmail(email);
UUID uuid = UUID.randomUUID();
String randomUuid = uuid.toString().substring(0, 6);
Mail mail = Mail.createAuthentication(email, randomUuid);
smtpService.sendMail(mail);

return randomUuid;
}

private String encodePassword(String password) {
return passwordEncoder.encode(password);
}

private void validateDuplicateEmail(String email) {
if (memberRepository.existsByEmail(email)) {
throw new MemberException(ExceptionCode.MEMBER_EMAIL_CONFLICT);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
import com.devtoon.jtoon.exception.ExceptionCode;
import com.devtoon.jtoon.exception.MemberException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum Gender {
MALE, FEMALE;
MALE,
FEMALE;

private static final Map<String, Gender> GENDER_MAP;

static {
GENDER_MAP = new HashMap<>();
Arrays.stream(Gender.values())
.forEach(gender -> GENDER_MAP.put(gender.name(), gender));
GENDER_MAP = Collections.unmodifiableMap(
Arrays.stream(Gender.values())
.collect(Collectors.toMap(Enum::name, Function.identity())));
}

public static Gender generate(String gender) {
public static Gender from(String gender) {
return Optional.ofNullable(GENDER_MAP.get(gender))
.orElseThrow(() -> new MemberException(ExceptionCode.MEMBER_GENDER_INVALID_FORMAT));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
import com.devtoon.jtoon.exception.ExceptionCode;
import com.devtoon.jtoon.exception.MemberException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum LoginType {
LOCAL,
NAVER,
Expand All @@ -15,12 +20,13 @@ public enum LoginType {
private static final Map<String, LoginType> LOGIN_TYPE_MAP;

static {
LOGIN_TYPE_MAP = new HashMap<>();
Arrays.stream(LoginType.values())
.forEach(loginType -> LOGIN_TYPE_MAP.put(loginType.name(), loginType));
LOGIN_TYPE_MAP = Collections.unmodifiableMap(
Arrays.stream(LoginType.values())
.collect(Collectors.toMap(LoginType::name, Function.identity()))
);
}

public static LoginType generate(String loginType) {
public static LoginType from(String loginType) {
return Optional.ofNullable(LOGIN_TYPE_MAP.get(loginType))
.orElseThrow(() -> new MemberException(ExceptionCode.MEMBER_LOGIN_TYPE_INVALID_FORMAT));
}
Expand Down
Loading

0 comments on commit d0a50a5

Please sign in to comment.