From f8a69346c75223b89d3bd9d4b0acf2914391cf39 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Thu, 27 Jun 2024 02:59:39 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat:=20mail=20=EC=A0=84=EC=86=A1=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++ .../clothstar/common/error/ErrorCode.java | 3 +- .../exception/MailSenderErrorException.java | 12 +++++++ .../exception/GlobalExceptionHandler.java | 11 ++++++ .../common/mail/MailContentBuilder.java | 19 +++++++++++ .../clothstar/common/mail/MailSendDTO.java | 14 ++++++++ .../clothstar/common/mail/MailService.java | 34 +++++++++++++++++++ src/main/resources/application-db.yml | 4 +-- src/main/resources/application.yml | 15 ++++++++ .../resources/templates/mailTemplate.html | 10 ++++++ .../common/config/JasyptConfigTest.java | 6 ++-- .../common/mail/MailServiceTest.java | 33 ++++++++++++++++++ src/test/resources/application-test.yml | 13 +++++++ 13 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java create mode 100644 src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java create mode 100644 src/main/java/org/store/clothstar/common/mail/MailSendDTO.java create mode 100644 src/main/java/org/store/clothstar/common/mail/MailService.java create mode 100644 src/main/resources/templates/mailTemplate.html create mode 100644 src/test/java/org/store/clothstar/common/mail/MailServiceTest.java diff --git a/build.gradle b/build.gradle index 29728dc4..e0e382e5 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,9 @@ dependencies { //yml 암호화, 공식문서: https://github.com/ulisesbocchio/jasypt-spring-boot //참고 블로그: https://velog.io/@bey1548/SpringBoot-application.yml-%EA%B0%92-%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EA%B8%B0jasypt implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5' + + //mail 전송 의존성 + implementation 'org.springframework.boot:spring-boot-starter-mail' } tasks.named('test') { diff --git a/src/main/java/org/store/clothstar/common/error/ErrorCode.java b/src/main/java/org/store/clothstar/common/error/ErrorCode.java index 3ac7a62b..25b7821d 100644 --- a/src/main/java/org/store/clothstar/common/error/ErrorCode.java +++ b/src/main/java/org/store/clothstar/common/error/ErrorCode.java @@ -6,7 +6,8 @@ @Getter public enum ErrorCode { NOT_FOUND_REFRESH_TOKEN(HttpStatus.NOT_FOUND, "refresh 토큰이 없습니다."), - INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "refresh 토큰이 만료되었거나 유효하지 않습니다."); + INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "refresh 토큰이 만료되었거나 유효하지 않습니다."), + ERROR_MAIL_SENDER(HttpStatus.BAD_REQUEST, "메일을 전송하는 도중 에러가 발생하였습니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java b/src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java new file mode 100644 index 00000000..eaf70ffe --- /dev/null +++ b/src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java @@ -0,0 +1,12 @@ +package org.store.clothstar.common.error.exception; + +import org.store.clothstar.common.error.ErrorCode; + +public class MailSenderErrorException extends RuntimeException { + private final ErrorCode errorCode; + + public MailSenderErrorException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } +} diff --git a/src/main/java/org/store/clothstar/common/exception/GlobalExceptionHandler.java b/src/main/java/org/store/clothstar/common/exception/GlobalExceptionHandler.java index 151b00b4..72946332 100644 --- a/src/main/java/org/store/clothstar/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/org/store/clothstar/common/exception/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.mail.MailException; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -35,6 +36,16 @@ protected ResponseEntity handleMethodArgumentNotValidExce return new ResponseEntity<>(validErrorResponseDTO, HttpStatus.BAD_REQUEST); } + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler + private ResponseEntity mailException(MailException ex) { + log.error("[MailException Handler] {}", ex.getMessage()); + ex.fillInStackTrace(); + ErrorResponseDTO errorResponseDTO = new ErrorResponseDTO(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage()); + + return new ResponseEntity<>(errorResponseDTO, HttpStatus.INTERNAL_SERVER_ERROR); + } + @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler private ResponseEntity illegalArgumentHandler(IllegalArgumentException ex) { diff --git a/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java b/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java new file mode 100644 index 00000000..eb331002 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java @@ -0,0 +1,19 @@ +package org.store.clothstar.common.mail; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + + +@Service +@RequiredArgsConstructor +public class MailContentBuilder { + private final TemplateEngine templateEngine; + + public String build(String message) { + Context context = new Context(); + context.setVariable("link", message); + return templateEngine.process("mailTemplate", context); + } +} diff --git a/src/main/java/org/store/clothstar/common/mail/MailSendDTO.java b/src/main/java/org/store/clothstar/common/mail/MailSendDTO.java new file mode 100644 index 00000000..8aaa5843 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/mail/MailSendDTO.java @@ -0,0 +1,14 @@ +package org.store.clothstar.common.mail; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class MailSendDTO { + private String address; + private String subject; + private String text; +} diff --git a/src/main/java/org/store/clothstar/common/mail/MailService.java b/src/main/java/org/store/clothstar/common/mail/MailService.java new file mode 100644 index 00000000..3cf82c32 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/mail/MailService.java @@ -0,0 +1,34 @@ +package org.store.clothstar.common.mail; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.mail.javamail.MimeMessagePreparator; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class MailService { + private final JavaMailSender mailSender; + + @Value("${email.send}") + private String fromAddress; + + public boolean sendMail(MailSendDTO mailSendDTO) { + MimeMessagePreparator messagePreparator = mimeMessage -> { + MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8"); + messageHelper.setFrom(fromAddress); + messageHelper.setTo(mailSendDTO.getAddress()); + messageHelper.setSubject(mailSendDTO.getSubject()); + messageHelper.setText(mailSendDTO.getText(), true); + }; + log.error("전송 메일주소 : {} -> {}", fromAddress, mailSendDTO.getAddress()); + + mailSender.send(messagePreparator); + + return true; + } +} diff --git a/src/main/resources/application-db.yml b/src/main/resources/application-db.yml index 2851e230..339e3049 100644 --- a/src/main/resources/application-db.yml +++ b/src/main/resources/application-db.yml @@ -49,9 +49,7 @@ spring: --- # dev 공통 설정 -jasypt: - encryptor: - bean: jasyptStringEncryptor + spring: config: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 28aad418..1173ab6f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,7 @@ +jasypt: + encryptor: + bean: jasyptStringEncryptor + spring: profiles: active: @@ -9,6 +13,17 @@ spring: - db-dev include: - db + mail: + host: smtp.gmail.com + port: 587 + username: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) + password: ENC(/hOuHdVpOgyzKrlqyayORlsTFpIrwe7RYnfAqXEFzIk=) + properties: + mail.smtp: + auth: true + enable: true + +email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) springdoc: default-consumes-media-type: application/json # 소비 미디어 타입 diff --git a/src/main/resources/templates/mailTemplate.html b/src/main/resources/templates/mailTemplate.html new file mode 100644 index 00000000..8ea7f02c --- /dev/null +++ b/src/main/resources/templates/mailTemplate.html @@ -0,0 +1,10 @@ + + + + 이메일 인증 링크 + + +계정 활성화를 위해서 아래의 인증 링크를 클릭해주세요.
+인증 링크 + + diff --git a/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java index 345c72f9..5371bf4b 100644 --- a/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java +++ b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java @@ -10,9 +10,9 @@ class JasyptConfigTest { @Test void jasypt() { String url = ""; - String username = ""; - String password = ""; - + String username = "nexthope22@gmail.com"; + String password = "pcde pppv pnxa dfmg"; + System.out.println(jasyptEncoding(url)); System.out.println(jasyptEncoding(username)); System.out.println(jasyptEncoding(password)); diff --git a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java new file mode 100644 index 00000000..ba6f2fda --- /dev/null +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -0,0 +1,33 @@ +package org.store.clothstar.common.mail; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("test") +class MailServiceTest { + @Autowired + MailService mailService; + @Autowired + MailContentBuilder mailContentBuilder; + + @DisplayName("메일 전송 테스트") + @Test + void mailSendTest() { + //given +// String link = Constants.ACTIVATION_EMAIL + "/" + token; + String link = "https://www.naver.com/"; + String message = mailContentBuilder.build(link); + MailSendDTO mailSendDTO = new MailSendDTO("", "test", message); + + //when + Boolean success = mailService.sendMail(mailSendDTO); + + //then + Assertions.assertThat(success).isTrue(); + } +} \ No newline at end of file diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 3883c060..91504f7f 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -9,6 +9,17 @@ spring: appender: com.p6spy.engine.spy.appender.Slf4JLogger logMessageFormat: p6spy: "%(currentTime)|%(executionTime)|%(category)|%(sqlSingleLine)" + mail: + host: smtp.gmail.com + port: 587 + username: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) + password: ENC(/hOuHdVpOgyzKrlqyayORlsTFpIrwe7RYnfAqXEFzIk=) + properties: + mail: + smtp: + auth: true + starttls: + enable: true jpa: hibernate: @@ -26,3 +37,5 @@ jwt: secret_key: Y2xvdGhzaG9wcGluZ21hbGxjbG90aHN0YXJjbG90aHNob3BwaW5nbWFsbGNsb3Roc3RhcmNsb3Roc2hvcHBpbmdtYWxsY2xvdGhzdGFyY2xvdGhzaG9wcGluZ21hbGxjbG90aHN0YXIK accessTokenValidTimeMillis: 120000 refreshTokenValidTimeMillis: 1200000 + +email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) \ No newline at end of file From 8ca28914729692a0a6685798866fedeaed373fb3 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Fri, 28 Jun 2024 02:44:08 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20mail=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/SecurityConfiguration.java | 2 +- .../common/config/jwt/LoginFilter.java | 17 ++++++++- .../application/MemberServiceApplication.java | 4 ++ .../controller/AuthenticationController.java | 17 ++++++--- .../member/domain/CustomUserDetails.java | 2 +- .../clothstar/member/entity/MemberEntity.java | 5 +++ .../member/service/MemberService.java | 2 + .../member/service/MemberServiceImpl.java | 38 +++++++++++++++---- src/main/resources/application.yml | 8 ++-- src/main/resources/sql/member.sql | 7 +++- 10 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/store/clothstar/common/config/SecurityConfiguration.java b/src/main/java/org/store/clothstar/common/config/SecurityConfiguration.java index 6a7e0f97..64a47bda 100644 --- a/src/main/java/org/store/clothstar/common/config/SecurityConfiguration.java +++ b/src/main/java/org/store/clothstar/common/config/SecurityConfiguration.java @@ -57,7 +57,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/v1/categories/**", "/v1/products/**", "/v1/productLines/**", "/v2/productLines/**", "/v1/orderdetails", "/v1/orders", "/v1/seller/orders/**", "/v1/seller/orders", "/v1/orders/**", - "/swagger-resources/**", "/swagger-ui/**", "/v3/api-docs/**" + "/swagger-resources/**", "/swagger-ui/**", "/v3/api-docs/**", "/v1/members/auth/**" ).permitAll() .requestMatchers(HttpMethod.POST, "/v1/members").permitAll() .requestMatchers(HttpMethod.POST, "/v1/sellers/**").authenticated() diff --git a/src/main/java/org/store/clothstar/common/config/jwt/LoginFilter.java b/src/main/java/org/store/clothstar/common/config/jwt/LoginFilter.java index e2b55696..7544103d 100644 --- a/src/main/java/org/store/clothstar/common/config/jwt/LoginFilter.java +++ b/src/main/java/org/store/clothstar/common/config/jwt/LoginFilter.java @@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -93,13 +95,26 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { log.info("로그인 실패"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); - MessageDTO messageDTO = MessageDTOBuilder.buildMessage(HttpServletResponse.SC_UNAUTHORIZED, "이메일 또는 비밀번호가 올바르지 않습니다. 다시 확인해주세요."); + MessageDTO messageDTO = MessageDTOBuilder.buildMessage(HttpServletResponse.SC_UNAUTHORIZED, errorMessage(failed)); ObjectMapper om = new ObjectMapper(); response.getWriter().print(om.writeValueAsString(messageDTO)); } + + private String errorMessage(AuthenticationException failed) { + String errorMessage = null; + + if (failed instanceof BadCredentialsException) { + errorMessage = "이메일 또는 비밀번호가 올바르지 않습니다. 다시 확인해주세요."; + } else if (failed instanceof DisabledException) { + errorMessage = "계정이 비활성화 되어있습니다. 이메일 인증을 완료해주세요"; + } + + return errorMessage; + } } diff --git a/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java b/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java index 5afe0cd2..a9abe90e 100644 --- a/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java +++ b/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java @@ -45,4 +45,8 @@ public void updateDeleteAt(Long memberId) { public Long signup(CreateMemberRequest createMemberDTO) { return memberService.signUp(createMemberDTO); } + + public void signupEmailAuthentication(Long memberId) { + memberService.signupEmailAuthentication(memberId); + } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java index 78f0fd4d..08a2601d 100644 --- a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java +++ b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java @@ -6,23 +6,23 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.store.clothstar.common.dto.SaveResponseDTO; import org.store.clothstar.member.application.MemberServiceApplication; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.MemberLoginRequest; @Tag(name = "Auth", description = "회원가입과 인증에 관한 API 입니다.") -@RestController +@Controller @RequiredArgsConstructor @Slf4j public class AuthenticationController { private final MemberServiceApplication memberServiceApplication; @Operation(summary = "회원가입", description = "회원가입시 회원 정보를 저장한다.") + @ResponseBody @PostMapping("/v1/members") public ResponseEntity signup(@Validated @RequestBody CreateMemberRequest createMemberDTO) { log.info("회원가입 요청 데이터 : {}", createMemberDTO.toString()); @@ -32,7 +32,7 @@ public ResponseEntity signup(@Validated @RequestBody CreateMemb SaveResponseDTO saveResponseDTO = SaveResponseDTO.builder() .id(memberId) .statusCode(HttpStatus.OK.value()) - .message("memberId : " + memberId + " 가 정상적으로 회원가입 되었습니다.") + .message(createMemberDTO.getEmail() + " 계정으로 인증메일이 전송 되었습니다.") .build(); return new ResponseEntity<>(saveResponseDTO, HttpStatus.CREATED); @@ -43,4 +43,11 @@ public ResponseEntity signup(@Validated @RequestBody CreateMemb public void login(@RequestBody MemberLoginRequest memberLoginRequest) { // 실제 로그인 로직은 Spring Security에서 처리 } + + @Operation(summary = "회원가입시 이메일 인증", description = "회원가입후 전송된 이메일에 링크를 클릭하면 회원이 활성화 된다.") + @GetMapping("/v1/members/auth/{id}") + public String signupEmailAuthentication(@PathVariable("id") Long memberId) { + memberServiceApplication.signupEmailAuthentication(memberId); + return "redirect:/login"; + } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java b/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java index 363e7aad..b2c1c28f 100644 --- a/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java +++ b/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java @@ -53,6 +53,6 @@ public boolean isCredentialsNonExpired() { @Override public boolean isEnabled() { //ture -> 계정 사용 가능 - return true; + return memberEntity.isEnabled(); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/entity/MemberEntity.java b/src/main/java/org/store/clothstar/member/entity/MemberEntity.java index 49b45ca7..f94af6f2 100644 --- a/src/main/java/org/store/clothstar/member/entity/MemberEntity.java +++ b/src/main/java/org/store/clothstar/member/entity/MemberEntity.java @@ -36,6 +36,7 @@ public class MemberEntity extends BaseEntity { private MemberRole role; @Enumerated(EnumType.STRING) private MemberGrade grade; + private boolean enabled; public MemberEntity(Member member) { this.memberId = member.getMemberId(); @@ -64,4 +65,8 @@ public void updatePassword(String password) { public void updateDeletedAt() { this.deletedAt = LocalDateTime.now(); } + + public void updateEnabled(boolean enabled) { + this.enabled = enabled; + } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/service/MemberService.java b/src/main/java/org/store/clothstar/member/service/MemberService.java index d0fdf297..54cccfd1 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberService.java +++ b/src/main/java/org/store/clothstar/member/service/MemberService.java @@ -20,4 +20,6 @@ public interface MemberService { void modifyMember(Long memberId, ModifyMemberRequest modifyMemberRequest); Long signUp(CreateMemberRequest createMemberDTO); + + void signupEmailAuthentication(Long memberId); } diff --git a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java index 9373688c..66e12dd5 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java +++ b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java @@ -1,11 +1,14 @@ package org.store.clothstar.member.service; +import jakarta.servlet.ServletContext; import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.store.clothstar.common.mail.MailContentBuilder; +import org.store.clothstar.common.mail.MailSendDTO; +import org.store.clothstar.common.mail.MailService; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.ModifyMemberRequest; import org.store.clothstar.member.dto.response.MemberResponse; @@ -22,16 +25,15 @@ */ @Service @Slf4j +@RequiredArgsConstructor @Transactional public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; private final PasswordEncoder passwordEncoder; + private final MailContentBuilder mailContentBuilder; + private final MailService mailService; + private final ServletContext context; - public MemberServiceImpl( - @Qualifier("memberJpaRepository") MemberRepository memberRepository) { - this.memberRepository = memberRepository; - this.passwordEncoder = new BCryptPasswordEncoder(); - } @Override public List findAll() { @@ -94,8 +96,28 @@ public Long signUp(CreateMemberRequest createMemberDTO) { String encodedPassword = passwordEncoder.encode(createMemberDTO.getPassword()); MemberEntity memberEntity = createMemberDTO.toMemberEntity(encodedPassword); + memberEntity.updateEnabled(false); memberEntity = memberRepository.save(memberEntity); + sendEmailAuthentication(memberEntity.getMemberId(), memberEntity.getEmail()); + return memberEntity.getMemberId(); } -} + + @Override + public void signupEmailAuthentication(Long memberId) { + MemberEntity memberEntity = memberRepository.findById(memberId) + .orElseThrow(() -> new IllegalArgumentException("not found by memberId: " + memberId)); + + memberEntity.updateEnabled(true); + log.info("이메일 인증 완료, email = {}", memberEntity.getEmail()); + } + + private void sendEmailAuthentication(Long memberId, String email) { + String link = "http://localhost:8080/v1/members/auth/" + memberId; + String message = mailContentBuilder.build(link); + MailSendDTO mailSendDTO = new MailSendDTO(email, "clothstar 회원가입 인증 메일 입니다.", message); + + mailService.sendMail(mailSendDTO); + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1173ab6f..773d4ef1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -19,9 +19,11 @@ spring: username: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) password: ENC(/hOuHdVpOgyzKrlqyayORlsTFpIrwe7RYnfAqXEFzIk=) properties: - mail.smtp: - auth: true - enable: true + mail: + smtp: + auth: true + starttls: + enable: true email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) diff --git a/src/main/resources/sql/member.sql b/src/main/resources/sql/member.sql index e9323c89..7cf5670a 100644 --- a/src/main/resources/sql/member.sql +++ b/src/main/resources/sql/member.sql @@ -12,6 +12,7 @@ CREATE TABLE `member` `created_at` timestamp NOT NULL, `modified_at` timestamp NULL, `deleted_at` timestamp NULL, + `enabled` boolean NOT NULL DEFAULT FALSE, CONSTRAINT PK_member PRIMARY KEY (member_id), CONSTRAINT UK_member_email UNIQUE (email) @@ -71,7 +72,7 @@ from seller; select * from productLine; select * -from member; +from member where email = 'rkdgustn@test.com'; select * from information_schema.table_constraints @@ -109,4 +110,6 @@ select * from seller; alter table member - change modified_at updated_at timestamp; \ No newline at end of file + change modified_at updated_at timestamp; + +ALTER TABLE member ADD COLUMN enabled boolean not null default false; From c41cf45320136222f991e113eb3271c9d23158e2 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Fri, 28 Jun 2024 02:53:56 +0900 Subject: [PATCH 3/9] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/store/clothstar/common/mail/MailServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java index ba6f2fda..52dbe187 100644 --- a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -22,7 +22,7 @@ void mailSendTest() { // String link = Constants.ACTIVATION_EMAIL + "/" + token; String link = "https://www.naver.com/"; String message = mailContentBuilder.build(link); - MailSendDTO mailSendDTO = new MailSendDTO("", "test", message); + MailSendDTO mailSendDTO = new MailSendDTO("test@test.com", "test", message); //when Boolean success = mailService.sendMail(mailSendDTO); From 5105f9568a8285205c17f270a707455c167fef5d Mon Sep 17 00:00:00 2001 From: hyunsu Date: Sun, 30 Jun 2024 22:20:58 +0900 Subject: [PATCH 4/9] =?UTF-8?q?chore:=20=EC=86=8C=EC=8A=A4=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/store/clothstar/common/mail/MailService.java | 2 +- .../org/store/clothstar/member/service/MemberServiceImpl.java | 3 --- .../java/org/store/clothstar/common/mail/MailServiceTest.java | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/store/clothstar/common/mail/MailService.java b/src/main/java/org/store/clothstar/common/mail/MailService.java index 3cf82c32..1022af2d 100644 --- a/src/main/java/org/store/clothstar/common/mail/MailService.java +++ b/src/main/java/org/store/clothstar/common/mail/MailService.java @@ -25,8 +25,8 @@ public boolean sendMail(MailSendDTO mailSendDTO) { messageHelper.setSubject(mailSendDTO.getSubject()); messageHelper.setText(mailSendDTO.getText(), true); }; - log.error("전송 메일주소 : {} -> {}", fromAddress, mailSendDTO.getAddress()); + log.info("전송 메일주소 : {} -> {}", fromAddress, mailSendDTO.getAddress()); mailSender.send(messagePreparator); return true; diff --git a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java index 66e12dd5..ce05d0e9 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java +++ b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java @@ -1,6 +1,5 @@ package org.store.clothstar.member.service; -import jakarta.servlet.ServletContext; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -32,8 +31,6 @@ public class MemberServiceImpl implements MemberService { private final PasswordEncoder passwordEncoder; private final MailContentBuilder mailContentBuilder; private final MailService mailService; - private final ServletContext context; - @Override public List findAll() { diff --git a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java index 52dbe187..c9e143f2 100644 --- a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -19,7 +19,6 @@ class MailServiceTest { @Test void mailSendTest() { //given -// String link = Constants.ACTIVATION_EMAIL + "/" + token; String link = "https://www.naver.com/"; String message = mailContentBuilder.build(link); MailSendDTO mailSendDTO = new MailSendDTO("test@test.com", "test", message); From fedd8f4c9eb66d512909a41fe018e36ad0794397 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Tue, 2 Jul 2024 00:14:49 +0900 Subject: [PATCH 5/9] =?UTF-8?q?build:=20redis=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ .../clothstar/common/config/RedisConfig.java | 21 +++++++++++++++++++ src/main/resources/application.yml | 5 +++++ src/test/resources/application-test.yml | 3 ++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/store/clothstar/common/config/RedisConfig.java diff --git a/build.gradle b/build.gradle index e0e382e5..d1f7819b 100644 --- a/build.gradle +++ b/build.gradle @@ -71,6 +71,9 @@ dependencies { //mail 전송 의존성 implementation 'org.springframework.boot:spring-boot-starter-mail' + + //Redis 의존성 + implementation 'org.springframework.boot:spring-boot-starter-data-redis' } tasks.named('test') { diff --git a/src/main/java/org/store/clothstar/common/config/RedisConfig.java b/src/main/java/org/store/clothstar/common/config/RedisConfig.java new file mode 100644 index 00000000..d7b3ad75 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/config/RedisConfig.java @@ -0,0 +1,21 @@ +package org.store.clothstar.common.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; + +@Configuration +public class RedisConfig { + @Value("${spring.data.redis.host}") + private String host; + + @Value("${spring.data.redis.port}") + private int port; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 773d4ef1..d818ec8b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -24,6 +24,11 @@ spring: auth: true starttls: enable: true + # Redis + data: + redis: + host: localhost + port: 6379 email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 91504f7f..0c076a70 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -38,4 +38,5 @@ jwt: accessTokenValidTimeMillis: 120000 refreshTokenValidTimeMillis: 1200000 -email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) \ No newline at end of file +email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) + From 487de65a1c654978423fcc461c69c087ed70fb3e Mon Sep 17 00:00:00 2001 From: hyunsu Date: Tue, 2 Jul 2024 23:31:02 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20redis=20util=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++- .../common/{config => redis}/RedisConfig.java | 2 +- .../clothstar/common/redis/RedisUtil.java | 34 +++++++++++++++++++ .../product/entity/ProductEntity.java | 2 ++ .../resources/templates/mailTemplate.html | 20 +++++++---- 5 files changed, 53 insertions(+), 9 deletions(-) rename src/main/java/org/store/clothstar/common/{config => redis}/RedisConfig.java (93%) create mode 100644 src/main/java/org/store/clothstar/common/redis/RedisUtil.java diff --git a/.gitignore b/.gitignore index 1fea113a..0a765de9 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,6 @@ out/ ### Custom Private Keys ### src/main/resources/app.key -src/main/resources/app.pub \ No newline at end of file +src/main/resources/app.pub + +!**/src/main/generated \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/common/config/RedisConfig.java b/src/main/java/org/store/clothstar/common/redis/RedisConfig.java similarity index 93% rename from src/main/java/org/store/clothstar/common/config/RedisConfig.java rename to src/main/java/org/store/clothstar/common/redis/RedisConfig.java index d7b3ad75..431ccb32 100644 --- a/src/main/java/org/store/clothstar/common/config/RedisConfig.java +++ b/src/main/java/org/store/clothstar/common/redis/RedisConfig.java @@ -1,4 +1,4 @@ -package org.store.clothstar.common.config; +package org.store.clothstar.common.redis; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/org/store/clothstar/common/redis/RedisUtil.java b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java new file mode 100644 index 00000000..85f21680 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java @@ -0,0 +1,34 @@ +package org.store.clothstar.common.redis; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Service; + +import java.time.Duration; + +@RequiredArgsConstructor +@Service +public class RedisUtil { + private final StringRedisTemplate template; + + public String getData(String key) { + ValueOperations valueOperations = template.opsForValue(); + return valueOperations.get(key); + } + + public boolean existData(String key) { + return Boolean.TRUE.equals(template.hasKey(key)); + } + + public void setDataExpire(String key, String value, long duration) { + ValueOperations valueOperations = template.opsForValue(); + Duration expireDuration = Duration.ofSeconds(duration); + valueOperations.set(key, value, expireDuration); + } + + public void deleteData(String key) { + template.delete(key); + } + +} diff --git a/src/main/java/org/store/clothstar/product/entity/ProductEntity.java b/src/main/java/org/store/clothstar/product/entity/ProductEntity.java index 675ff27c..061b6493 100644 --- a/src/main/java/org/store/clothstar/product/entity/ProductEntity.java +++ b/src/main/java/org/store/clothstar/product/entity/ProductEntity.java @@ -50,6 +50,7 @@ public void updateStock(long stock) { checkAndUpdateProductLineStatus(); } + // 재고를 차감하고 상태를 변경하는 메서드 public void reduceStock(int quantity) { if (this.stock >= quantity) { this.stock -= quantity; @@ -59,6 +60,7 @@ public void reduceStock(int quantity) { } } + // 재고 변경 시 ProductLine 상태 업데이트 메서드 private void checkAndUpdateProductLineStatus() { if (productLine != null) { productLine.checkAndUpdateStatus(); diff --git a/src/main/resources/templates/mailTemplate.html b/src/main/resources/templates/mailTemplate.html index 8ea7f02c..98d6b29d 100644 --- a/src/main/resources/templates/mailTemplate.html +++ b/src/main/resources/templates/mailTemplate.html @@ -1,10 +1,16 @@ - - - 이메일 인증 링크 - + -계정 활성화를 위해서 아래의 인증 링크를 클릭해주세요.
-인증 링크 +
+
+

인증 코드 메일입니다.

+
+

아래 코드를 사이트에 입력해주십시오

+
+
+

+
+
+
- + \ No newline at end of file From d53e58874ba98b5facf029be96268b90f903b65b Mon Sep 17 00:00:00 2001 From: hyunsu Date: Wed, 3 Jul 2024 03:37:42 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20redis=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clothstar/common/error/ErrorCode.java | 2 +- ... SignupCertifyNumAuthFailedException.java} | 4 +- .../common/exception/ExceptionType.java | 2 - .../common/mail/MailContentBuilder.java | 6 +- .../clothstar/common/redis/RedisUtil.java | 7 +- .../application/MemberServiceApplication.java | 4 +- .../controller/AuthenticationController.java | 12 ++-- .../member/domain/CustomUserDetails.java | 2 +- .../dto/request/CreateMemberRequest.java | 23 +------ .../member/service/MemberService.java | 4 +- .../member/service/MemberServiceImpl.java | 68 +++++++++++++++---- .../exception/ProductLineExceptionType.java | 1 - src/main/resources/application.yml | 1 + src/main/resources/static/js/signup.js | 26 ++++++- .../resources/templates/mailTemplate.html | 6 +- src/main/resources/templates/signup.html | 7 ++ .../clothstar/common/redis/RedisUtilTest.java | 29 ++++++++ 17 files changed, 145 insertions(+), 59 deletions(-) rename src/main/java/org/store/clothstar/common/error/exception/{MailSenderErrorException.java => SignupCertifyNumAuthFailedException.java} (60%) create mode 100644 src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java diff --git a/src/main/java/org/store/clothstar/common/error/ErrorCode.java b/src/main/java/org/store/clothstar/common/error/ErrorCode.java index 25b7821d..3c4b3096 100644 --- a/src/main/java/org/store/clothstar/common/error/ErrorCode.java +++ b/src/main/java/org/store/clothstar/common/error/ErrorCode.java @@ -7,7 +7,7 @@ public enum ErrorCode { NOT_FOUND_REFRESH_TOKEN(HttpStatus.NOT_FOUND, "refresh 토큰이 없습니다."), INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "refresh 토큰이 만료되었거나 유효하지 않습니다."), - ERROR_MAIL_SENDER(HttpStatus.BAD_REQUEST, "메일을 전송하는 도중 에러가 발생하였습니다."); + INVALID_AUTH_CERTIFY_NUM(HttpStatus.BAD_REQUEST, "인증번호가 잘못 되었습니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java b/src/main/java/org/store/clothstar/common/error/exception/SignupCertifyNumAuthFailedException.java similarity index 60% rename from src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java rename to src/main/java/org/store/clothstar/common/error/exception/SignupCertifyNumAuthFailedException.java index eaf70ffe..35d58fd4 100644 --- a/src/main/java/org/store/clothstar/common/error/exception/MailSenderErrorException.java +++ b/src/main/java/org/store/clothstar/common/error/exception/SignupCertifyNumAuthFailedException.java @@ -2,10 +2,10 @@ import org.store.clothstar.common.error.ErrorCode; -public class MailSenderErrorException extends RuntimeException { +public class SignupCertifyNumAuthFailedException extends RuntimeException { private final ErrorCode errorCode; - public MailSenderErrorException(ErrorCode errorCode) { + public SignupCertifyNumAuthFailedException(ErrorCode errorCode) { super(errorCode.getMessage()); this.errorCode = errorCode; } diff --git a/src/main/java/org/store/clothstar/common/exception/ExceptionType.java b/src/main/java/org/store/clothstar/common/exception/ExceptionType.java index f48557bc..1b7590d2 100644 --- a/src/main/java/org/store/clothstar/common/exception/ExceptionType.java +++ b/src/main/java/org/store/clothstar/common/exception/ExceptionType.java @@ -5,7 +5,5 @@ public interface ExceptionType { HttpStatus status(); - int exceptionCode(); - String message(); } diff --git a/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java b/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java index eb331002..53b08264 100644 --- a/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java +++ b/src/main/java/org/store/clothstar/common/mail/MailContentBuilder.java @@ -11,9 +11,9 @@ public class MailContentBuilder { private final TemplateEngine templateEngine; - public String build(String message) { + public String build(String certifyNum) { Context context = new Context(); - context.setVariable("link", message); + context.setVariable("certifyNum", certifyNum); return templateEngine.process("mailTemplate", context); } -} +} \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/common/redis/RedisUtil.java b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java index 85f21680..14fd676e 100644 --- a/src/main/java/org/store/clothstar/common/redis/RedisUtil.java +++ b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java @@ -1,6 +1,7 @@ package org.store.clothstar.common.redis; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; @@ -12,6 +13,9 @@ public class RedisUtil { private final StringRedisTemplate template; + @Value("${spring.data.redis.duration}") + private int duration; + public String getData(String key) { ValueOperations valueOperations = template.opsForValue(); return valueOperations.get(key); @@ -21,7 +25,7 @@ public boolean existData(String key) { return Boolean.TRUE.equals(template.hasKey(key)); } - public void setDataExpire(String key, String value, long duration) { + public void setDataExpire(String key, String value) { ValueOperations valueOperations = template.opsForValue(); Duration expireDuration = Duration.ofSeconds(duration); valueOperations.set(key, value, expireDuration); @@ -30,5 +34,4 @@ public void setDataExpire(String key, String value, long duration) { public void deleteData(String key) { template.delete(key); } - } diff --git a/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java b/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java index a9abe90e..4ac4cc8b 100644 --- a/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java +++ b/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java @@ -46,7 +46,7 @@ public Long signup(CreateMemberRequest createMemberDTO) { return memberService.signUp(createMemberDTO); } - public void signupEmailAuthentication(Long memberId) { - memberService.signupEmailAuthentication(memberId); + public void signupCertifyNumEmailSend(String email) { + memberService.signupCertifyNumEmailSend(email); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java index 08a2601d..f0c6c2f8 100644 --- a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java +++ b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java @@ -32,7 +32,7 @@ public ResponseEntity signup(@Validated @RequestBody CreateMemb SaveResponseDTO saveResponseDTO = SaveResponseDTO.builder() .id(memberId) .statusCode(HttpStatus.OK.value()) - .message(createMemberDTO.getEmail() + " 계정으로 인증메일이 전송 되었습니다.") + .message(createMemberDTO.getEmail() + " 아이디로 회원가입이 완료 되었습니다.") .build(); return new ResponseEntity<>(saveResponseDTO, HttpStatus.CREATED); @@ -44,10 +44,10 @@ public void login(@RequestBody MemberLoginRequest memberLoginRequest) { // 실제 로그인 로직은 Spring Security에서 처리 } - @Operation(summary = "회원가입시 이메일 인증", description = "회원가입후 전송된 이메일에 링크를 클릭하면 회원이 활성화 된다.") - @GetMapping("/v1/members/auth/{id}") - public String signupEmailAuthentication(@PathVariable("id") Long memberId) { - memberServiceApplication.signupEmailAuthentication(memberId); - return "redirect:/login"; + @Operation(summary = "이메일로 인증번호 전송", description = "기입한 이메일로 인증번호를 전송합니다.") + @ResponseBody + @GetMapping("/v1/members/auth/{email}") + public void signupEmailAuthentication(@PathVariable("email") String email) { + memberServiceApplication.signupCertifyNumEmailSend(email); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java b/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java index b2c1c28f..363e7aad 100644 --- a/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java +++ b/src/main/java/org/store/clothstar/member/domain/CustomUserDetails.java @@ -53,6 +53,6 @@ public boolean isCredentialsNonExpired() { @Override public boolean isEnabled() { //ture -> 계정 사용 가능 - return memberEntity.isEnabled(); + return true; } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java b/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java index 7994add1..15dd7901 100644 --- a/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java +++ b/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java @@ -1,17 +1,11 @@ package org.store.clothstar.member.dto.request; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.*; import lombok.*; -import org.store.clothstar.member.domain.Member; import org.store.clothstar.member.domain.MemberGrade; import org.store.clothstar.member.domain.MemberRole; import org.store.clothstar.member.entity.MemberEntity; -import java.time.LocalDateTime; - @Getter @AllArgsConstructor @NoArgsConstructor @@ -30,19 +24,8 @@ public class CreateMemberRequest { @Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "유효하지 않은 전화번호 형식입니다.") private String telNo; - public Member toMember(String encryptedPassword) { - return Member.builder() - .email(email) - .password(encryptedPassword) - .name(name) - .telNo(telNo) - .totalPaymentPrice(0) - .point(0) - .role(MemberRole.USER) - .grade(MemberGrade.BRONZE) - .createdAt(LocalDateTime.now()) - .build(); - } + @NotNull(message = "인증번호를 입력해 주세요") + private String certifyNum; public MemberEntity toMemberEntity(String encryptedPassword) { return MemberEntity.builder() diff --git a/src/main/java/org/store/clothstar/member/service/MemberService.java b/src/main/java/org/store/clothstar/member/service/MemberService.java index 54cccfd1..1fa8fc47 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberService.java +++ b/src/main/java/org/store/clothstar/member/service/MemberService.java @@ -21,5 +21,5 @@ public interface MemberService { Long signUp(CreateMemberRequest createMemberDTO); - void signupEmailAuthentication(Long memberId); -} + void signupCertifyNumEmailSend(String email); +} \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java index ce05d0e9..106be427 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java +++ b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java @@ -5,9 +5,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.store.clothstar.common.error.ErrorCode; +import org.store.clothstar.common.error.exception.SignupCertifyNumAuthFailedException; import org.store.clothstar.common.mail.MailContentBuilder; import org.store.clothstar.common.mail.MailSendDTO; import org.store.clothstar.common.mail.MailService; +import org.store.clothstar.common.redis.RedisUtil; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.ModifyMemberRequest; import org.store.clothstar.member.dto.response.MemberResponse; @@ -15,6 +18,7 @@ import org.store.clothstar.member.repository.MemberRepository; import java.util.List; +import java.util.Random; import java.util.stream.Collectors; /** @@ -31,6 +35,7 @@ public class MemberServiceImpl implements MemberService { private final PasswordEncoder passwordEncoder; private final MailContentBuilder mailContentBuilder; private final MailService mailService; + private final RedisUtil redisUtil; @Override public List findAll() { @@ -93,28 +98,65 @@ public Long signUp(CreateMemberRequest createMemberDTO) { String encodedPassword = passwordEncoder.encode(createMemberDTO.getPassword()); MemberEntity memberEntity = createMemberDTO.toMemberEntity(encodedPassword); - memberEntity.updateEnabled(false); - memberEntity = memberRepository.save(memberEntity); - sendEmailAuthentication(memberEntity.getMemberId(), memberEntity.getEmail()); + //인증코드 확인 + boolean certifyStatus = verifyEmailCode(memberEntity.getEmail(), createMemberDTO.getCertifyNum()); + if (certifyStatus) { + memberEntity = memberRepository.save(memberEntity); + } else { + throw new SignupCertifyNumAuthFailedException(ErrorCode.INVALID_AUTH_CERTIFY_NUM); + } return memberEntity.getMemberId(); } @Override - public void signupEmailAuthentication(Long memberId) { - MemberEntity memberEntity = memberRepository.findById(memberId) - .orElseThrow(() -> new IllegalArgumentException("not found by memberId: " + memberId)); - - memberEntity.updateEnabled(true); - log.info("이메일 인증 완료, email = {}", memberEntity.getEmail()); + public void signupCertifyNumEmailSend(String email) { + sendEmailAuthentication(email); + log.info("인증번호 전송 완료, email = {}", email); } - private void sendEmailAuthentication(Long memberId, String email) { - String link = "http://localhost:8080/v1/members/auth/" + memberId; - String message = mailContentBuilder.build(link); - MailSendDTO mailSendDTO = new MailSendDTO(email, "clothstar 회원가입 인증 메일 입니다.", message); + private String sendEmailAuthentication(String toEmail) { + String certifyNum = createdCode(); + String message = mailContentBuilder.build(certifyNum); + MailSendDTO mailSendDTO = new MailSendDTO(toEmail, "clothstar 회원가입 인증 메일 입니다.", message); mailService.sendMail(mailSendDTO); + + //메일 전송에 성공하면 redis에 key = email, value = 인증번호를 생성한다. + //지속시간은 10분 + createRedis(toEmail, certifyNum); + + return certifyNum; + } + + public Boolean verifyEmailCode(String email, String certifyNum) { + String codeFoundByEmail = redisUtil.getData(email); + if (codeFoundByEmail == null) { + return false; + } + + return codeFoundByEmail.equals(certifyNum); + } + + private void createRedis(String toEmail, String code) { + if (redisUtil.existData(toEmail)) { + redisUtil.deleteData(toEmail); + } + + redisUtil.setDataExpire(toEmail, code); + } + + private String createdCode() { + int leftLimit = 48; // number '0' + int rightLimit = 122; // alphabet 'z' + int targetStringLength = 6; + Random random = new Random(); + + return random.ints(leftLimit, rightLimit + 1) + .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97)) + .limit(targetStringLength) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) + .toString(); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/productLine/exception/ProductLineExceptionType.java b/src/main/java/org/store/clothstar/productLine/exception/ProductLineExceptionType.java index 1343c279..ba245450 100644 --- a/src/main/java/org/store/clothstar/productLine/exception/ProductLineExceptionType.java +++ b/src/main/java/org/store/clothstar/productLine/exception/ProductLineExceptionType.java @@ -17,7 +17,6 @@ public HttpStatus status() { return status; } - @Override public int exceptionCode() { return exceptionCode; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d818ec8b..406af5ca 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -29,6 +29,7 @@ spring: redis: host: localhost port: 6379 + duration: 600 email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) diff --git a/src/main/resources/static/js/signup.js b/src/main/resources/static/js/signup.js index c0aeae7f..3874c917 100644 --- a/src/main/resources/static/js/signup.js +++ b/src/main/resources/static/js/signup.js @@ -1,4 +1,27 @@ const createButton = document.getElementById("create-btn"); +const certifyNumEmailSendButton = document.getElementById("certifyNum-btn"); + +if (certifyNumEmailSendButton) { + certifyNumEmailSendButton.addEventListener("click", (event) => { + const emailValue = document.getElementById("email").value; + if (emailValue == null || emailValue == "") { + alert("이메일을 입력해 주세요"); + } else { + fetch(`/v1/members/auth/${emailValue}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }).then((res) => { + if (res.ok) { + alert("인증번호가 전송 되었습니다.") + } + }).catch(() => { + console.log("catch"); + }); + } + }); +} if (createButton) { createButton.addEventListener("click", (event) => { @@ -12,6 +35,7 @@ if (createButton) { password: document.getElementById("password").value, name: document.getElementById("name").value, telNo: document.getElementById("telNo").value, + certifyNum: document.getElementById("certifyNum").value, }), }).then((res) => res.json()) .then((res) => { @@ -24,7 +48,7 @@ if (createButton) { }).catch(() => { alert("ajax 호출 에러") }); - }) + }); } const emailCheck = () => { diff --git a/src/main/resources/templates/mailTemplate.html b/src/main/resources/templates/mailTemplate.html index 98d6b29d..e2c5b804 100644 --- a/src/main/resources/templates/mailTemplate.html +++ b/src/main/resources/templates/mailTemplate.html @@ -5,10 +5,10 @@

인증 코드 메일입니다.


-

아래 코드를 사이트에 입력해주십시오

+

아래 코드를 사이트에 입력해주십시오

-
-

+
+


diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html index be031c8f..3041926b 100644 --- a/src/main/resources/templates/signup.html +++ b/src/main/resources/templates/signup.html @@ -38,6 +38,13 @@

SIGN UP

+
+ +
+ + +
+
diff --git a/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java b/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java new file mode 100644 index 00000000..3a2a24c8 --- /dev/null +++ b/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java @@ -0,0 +1,29 @@ +package org.store.clothstar.common.redis; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class RedisUtilTest { + + @Autowired + private RedisUtil redisUtil; + + + @Test + public void redisTest() throws Exception { + //given + String email = "test@test.com"; + String code = "aaa111"; + + //when + redisUtil.setDataExpire(email, code); + + //then + Assertions.assertTrue(redisUtil.existData("test@test.com")); + Assertions.assertFalse(redisUtil.existData("test1@test.com")); + Assertions.assertEquals(redisUtil.getData(email), "aaa111"); + } +} \ No newline at end of file From 0d815d31ea0c7034b80e4a61ae6e29ba3931bdf7 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Thu, 4 Jul 2024 04:08:21 +0900 Subject: [PATCH 8/9] =?UTF-8?q?test:=20redis=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=EA=B3=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clothstar/common/redis/RedisUtil.java | 22 ++++++++ .../controller/AuthenticationController.java | 16 +++--- .../member/dto/request/CertifyNumRequest.java | 14 +++++ .../dto/request/CreateMemberRequest.java | 13 +++++ .../member/service/MemberServiceImpl.java | 26 +--------- src/main/resources/static/js/signup.js | 7 ++- .../jwt/JwtControllerIntegrationTest.java | 26 +--------- .../common/mail/MailServiceTest.java | 2 + .../AddressControllerIntegrationTest.java | 13 +++-- .../MemberAndSellerSignUpIntegrationTest.java | 52 +++++++------------ .../SellerControllerIntegrationTest.java | 13 ++++- .../service/MemberServiceJpaUnitTest.java | 21 ++------ .../SellerCreateJpaServiceUnitTest.java | 40 +++++--------- .../clothstar/member/util/CreateObject.java | 38 ++++++++++++++ 14 files changed, 161 insertions(+), 142 deletions(-) create mode 100644 src/main/java/org/store/clothstar/member/dto/request/CertifyNumRequest.java create mode 100644 src/test/java/org/store/clothstar/member/util/CreateObject.java diff --git a/src/main/java/org/store/clothstar/common/redis/RedisUtil.java b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java index 14fd676e..aa0472f4 100644 --- a/src/main/java/org/store/clothstar/common/redis/RedisUtil.java +++ b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import java.time.Duration; +import java.util.Random; @RequiredArgsConstructor @Service @@ -34,4 +35,25 @@ public void setDataExpire(String key, String value) { public void deleteData(String key) { template.delete(key); } + + public void createRedisData(String toEmail, String code) { + if (existData(toEmail)) { + deleteData(toEmail); + } + + setDataExpire(toEmail, code); + } + + public String createdCertifyNum() { + int leftLimit = 48; // number '0' + int rightLimit = 122; // alphabet 'z' + int targetStringLength = 6; + Random random = new Random(); + + return random.ints(leftLimit, rightLimit + 1) + .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97)) + .limit(targetStringLength) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) + .toString(); + } } diff --git a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java index f0c6c2f8..14f0fad1 100644 --- a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java +++ b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java @@ -6,23 +6,24 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; import org.store.clothstar.common.dto.SaveResponseDTO; import org.store.clothstar.member.application.MemberServiceApplication; +import org.store.clothstar.member.dto.request.CertifyNumRequest; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.MemberLoginRequest; @Tag(name = "Auth", description = "회원가입과 인증에 관한 API 입니다.") -@Controller +@RestController @RequiredArgsConstructor @Slf4j public class AuthenticationController { private final MemberServiceApplication memberServiceApplication; @Operation(summary = "회원가입", description = "회원가입시 회원 정보를 저장한다.") - @ResponseBody @PostMapping("/v1/members") public ResponseEntity signup(@Validated @RequestBody CreateMemberRequest createMemberDTO) { log.info("회원가입 요청 데이터 : {}", createMemberDTO.toString()); @@ -45,9 +46,8 @@ public void login(@RequestBody MemberLoginRequest memberLoginRequest) { } @Operation(summary = "이메일로 인증번호 전송", description = "기입한 이메일로 인증번호를 전송합니다.") - @ResponseBody - @GetMapping("/v1/members/auth/{email}") - public void signupEmailAuthentication(@PathVariable("email") String email) { - memberServiceApplication.signupCertifyNumEmailSend(email); + @PostMapping("/v1/members/auth") + public void signupEmailAuthentication(@Validated @RequestBody CertifyNumRequest certifyNumRequest) { + memberServiceApplication.signupCertifyNumEmailSend(certifyNumRequest.getEmail()); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/dto/request/CertifyNumRequest.java b/src/main/java/org/store/clothstar/member/dto/request/CertifyNumRequest.java new file mode 100644 index 00000000..011c2238 --- /dev/null +++ b/src/main/java/org/store/clothstar/member/dto/request/CertifyNumRequest.java @@ -0,0 +1,14 @@ +package org.store.clothstar.member.dto.request; + +import jakarta.validation.constraints.NotNull; +import lombok.*; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +public class CertifyNumRequest { + @NotNull(message = "이메일을 입력해 주세요") + private String email; +} \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java b/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java index 15dd7901..568b45b1 100644 --- a/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java +++ b/src/main/java/org/store/clothstar/member/dto/request/CreateMemberRequest.java @@ -39,4 +39,17 @@ public MemberEntity toMemberEntity(String encryptedPassword) { .grade(MemberGrade.BRONZE) .build(); } + + public MemberEntity toMemberEntity() { + return MemberEntity.builder() + .email(email) + .password(password) + .name(name) + .telNo(telNo) + .totalPaymentPrice(0) + .point(0) + .role(MemberRole.USER) + .grade(MemberGrade.BRONZE) + .build(); + } } diff --git a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java index 106be427..df36d0d0 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java +++ b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java @@ -18,7 +18,6 @@ import org.store.clothstar.member.repository.MemberRepository; import java.util.List; -import java.util.Random; import java.util.stream.Collectors; /** @@ -117,7 +116,7 @@ public void signupCertifyNumEmailSend(String email) { } private String sendEmailAuthentication(String toEmail) { - String certifyNum = createdCode(); + String certifyNum = redisUtil.createdCertifyNum(); String message = mailContentBuilder.build(certifyNum); MailSendDTO mailSendDTO = new MailSendDTO(toEmail, "clothstar 회원가입 인증 메일 입니다.", message); @@ -125,7 +124,7 @@ private String sendEmailAuthentication(String toEmail) { //메일 전송에 성공하면 redis에 key = email, value = 인증번호를 생성한다. //지속시간은 10분 - createRedis(toEmail, certifyNum); + redisUtil.createRedisData(toEmail, certifyNum); return certifyNum; } @@ -138,25 +137,4 @@ public Boolean verifyEmailCode(String email, String certifyNum) { return codeFoundByEmail.equals(certifyNum); } - - private void createRedis(String toEmail, String code) { - if (redisUtil.existData(toEmail)) { - redisUtil.deleteData(toEmail); - } - - redisUtil.setDataExpire(toEmail, code); - } - - private String createdCode() { - int leftLimit = 48; // number '0' - int rightLimit = 122; // alphabet 'z' - int targetStringLength = 6; - Random random = new Random(); - - return random.ints(leftLimit, rightLimit + 1) - .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97)) - .limit(targetStringLength) - .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) - .toString(); - } } \ No newline at end of file diff --git a/src/main/resources/static/js/signup.js b/src/main/resources/static/js/signup.js index 3874c917..55cad551 100644 --- a/src/main/resources/static/js/signup.js +++ b/src/main/resources/static/js/signup.js @@ -7,11 +7,14 @@ if (certifyNumEmailSendButton) { if (emailValue == null || emailValue == "") { alert("이메일을 입력해 주세요"); } else { - fetch(`/v1/members/auth/${emailValue}`, { - method: "GET", + fetch(`/v1/members/auth`, { + method: "POST", headers: { "Content-Type": "application/json", }, + body: JSON.stringify({ + email: emailValue + }), }).then((res) => { if (res.ok) { alert("인증번호가 전송 되었습니다.") diff --git a/src/test/java/org/store/clothstar/common/config/jwt/JwtControllerIntegrationTest.java b/src/test/java/org/store/clothstar/common/config/jwt/JwtControllerIntegrationTest.java index d20ee6df..85e5e39f 100644 --- a/src/test/java/org/store/clothstar/common/config/jwt/JwtControllerIntegrationTest.java +++ b/src/test/java/org/store/clothstar/common/config/jwt/JwtControllerIntegrationTest.java @@ -11,10 +11,9 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.transaction.annotation.Transactional; -import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.entity.MemberEntity; import org.store.clothstar.member.repository.MemberRepository; -import org.store.clothstar.member.service.MemberService; +import org.store.clothstar.member.util.CreateObject; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -27,29 +26,21 @@ @ActiveProfiles("test") @Transactional class JwtControllerIntegrationTest { - @Autowired - private JwtController jwtController; - @Autowired private JwtUtil jwtUtil; @Autowired private MockMvc mockMvc; - @Autowired - private MemberService memberService; - @Autowired private MemberRepository memberRepository; - private Long memberId; private MemberEntity memberEntity; @DisplayName("회원가입한 멤버아이디와, 인증에 필요한 access 토큰을 가져옵니다.") @BeforeEach public void getMemberId_getAccessToken() { - memberId = memberService.signUp(getCreateMemberRequest()); - memberEntity = memberRepository.findById(memberId).get(); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); } @DisplayName("refresh 토큰으로 access 토큰을 가져온다.") @@ -69,17 +60,4 @@ void accessToken_reissue_by_RefreshToken() throws Exception { actions.andDo(print()); actions.andExpect(jsonPath("$.accessToken").isNotEmpty()); } - - private CreateMemberRequest getCreateMemberRequest() { - String email = "test11@naver.com"; - String password = "testl122sff"; - String name = "name"; - String telNo = "010-1234-1245"; - - CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo - ); - - return createMemberRequest; - } } \ No newline at end of file diff --git a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java index c9e143f2..ded32e15 100644 --- a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -1,6 +1,7 @@ package org.store.clothstar.common.mail; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -9,6 +10,7 @@ @SpringBootTest @ActiveProfiles("test") +@Disabled class MailServiceTest { @Autowired MailService mailService; diff --git a/src/test/java/org/store/clothstar/member/controller/AddressControllerIntegrationTest.java b/src/test/java/org/store/clothstar/member/controller/AddressControllerIntegrationTest.java index 9f2b5c10..e4229298 100644 --- a/src/test/java/org/store/clothstar/member/controller/AddressControllerIntegrationTest.java +++ b/src/test/java/org/store/clothstar/member/controller/AddressControllerIntegrationTest.java @@ -24,6 +24,7 @@ import org.store.clothstar.member.repository.MemberRepository; import org.store.clothstar.member.service.AddressServiceImpl; import org.store.clothstar.member.service.MemberService; +import org.store.clothstar.member.util.CreateObject; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -58,16 +59,17 @@ class AddressControllerIntegrationTest { private JwtUtil jwtUtil; private static final String ADDRESS_URL = "/v1/members/addresses/"; + + private MemberEntity memberEntity; private Long memberId; private String accessToken; - private MemberEntity member; @DisplayName("회원가입한 멤버아이디와, 인증에 필요한 access 토큰을 가져옵니다.") @BeforeEach public void getMemberId_getAccessToken() { - memberId = memberService.signUp(getCreateMemberRequest()); - member = memberRepository.findById(memberId).get(); - accessToken = jwtUtil.createAccessToken(member); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + memberId = memberEntity.getMemberId(); + accessToken = jwtUtil.createAccessToken(memberEntity); } @DisplayName("회원 배송지 저장 통합 테스트") @@ -155,9 +157,10 @@ private CreateMemberRequest getCreateMemberRequest() { String password = "testl122sff"; String name = "name"; String telNo = "010-1234-1245"; + String certifyNum = "123asdf"; CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo + email, password, name, telNo, certifyNum ); return createMemberRequest; diff --git a/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java b/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java index 470180d9..4dff33e1 100644 --- a/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java +++ b/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -15,13 +16,12 @@ import org.springframework.transaction.annotation.Transactional; import org.store.clothstar.common.config.jwt.JwtUtil; import org.store.clothstar.member.domain.MemberRole; -import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.CreateSellerRequest; import org.store.clothstar.member.dto.request.ModifyMemberRequest; import org.store.clothstar.member.dto.request.ModifyPasswordRequest; import org.store.clothstar.member.entity.MemberEntity; import org.store.clothstar.member.repository.MemberRepository; -import org.store.clothstar.member.service.MemberService; +import org.store.clothstar.member.util.CreateObject; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -46,20 +46,18 @@ class MemberAndSellerSignUpIntegrationTest { @Autowired private MemberRepository memberRepository; - @Autowired - private MemberService memberService; - private static final String MEMBER_URL = "/v1/members"; private static final String SELLER_URL = "/v1/sellers"; + private MemberEntity memberEntity; @DisplayName("회원가입을 완료한 후 memberId와 accessToken을 받아서 판매자 가입을 신청한 테스트이다.") @WithMockUser + @Disabled @Test void signUpAndSellerTest() throws Exception { //회원가입 통합 테스트 //given - CreateMemberRequest createMemberRequest = getCreateMemberRequest("test@naver.com"); - final String requestBody = objectMapper.writeValueAsString(createMemberRequest); + final String requestBody = objectMapper.writeValueAsString(CreateObject.getCreateMemberRequest()); //when ResultActions actions = mockMvc.perform(post(MEMBER_URL) @@ -96,9 +94,9 @@ void signUpAndSellerTest() throws Exception { @Test void getAllMemberTest() throws Exception { //given 3명의 회원을 만든다. - memberService.signUp(getCreateMemberRequest("test1@naver.com")); - memberService.signUp(getCreateMemberRequest("test2@naver.com")); - memberService.signUp(getCreateMemberRequest("test3@naver.com")); + memberRepository.save(CreateObject.getCreateMemberRequest("test1@naver.com").toMemberEntity()); + memberRepository.save(CreateObject.getCreateMemberRequest("test2@naver.com").toMemberEntity()); + memberRepository.save(CreateObject.getCreateMemberRequest("test3@naver.com").toMemberEntity()); //when ResultActions actions = mockMvc.perform(get(MEMBER_URL) @@ -115,7 +113,8 @@ void getAllMemberTest() throws Exception { @Test void getMemberTest() throws Exception { //given - Long memberId = memberService.signUp(getCreateMemberRequest("test1@naver.com")); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + Long memberId = memberEntity.getMemberId(); String getMemberURL = MEMBER_URL + "/" + memberId; //when @@ -131,9 +130,8 @@ void getMemberTest() throws Exception { @Test void emailDuplicationCheckTest() throws Exception { //given - String email = "dupltest@naver.com"; - Long memberId = memberService.signUp(getCreateMemberRequest(email)); - String emailDuplicationCheckURL = MEMBER_URL + "/email/" + email; + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + String emailDuplicationCheckURL = MEMBER_URL + "/email/" + memberEntity.getEmail(); //when ResultActions actions = mockMvc.perform(get(emailDuplicationCheckURL) @@ -149,7 +147,8 @@ void emailDuplicationCheckTest() throws Exception { @Test void modifyName_modifyAuth_MemberTest() throws Exception { //given - Long memberId = memberService.signUp(getCreateMemberRequest("test1@naver.com")); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + Long memberId = memberEntity.getMemberId(); String modifyMemberURL = MEMBER_URL + "/" + memberId; ModifyMemberRequest modifyMemberRequest = ModifyMemberRequest.builder() .name("관리자") @@ -176,10 +175,9 @@ void modifyName_modifyAuth_MemberTest() throws Exception { @Test void modifyPasswordMemberTest() throws Exception { //given - Long memberId = memberService.signUp(getCreateMemberRequest("test1@naver.com")); - MemberEntity memberEntity = memberRepository.findById(memberId).get(); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); final String originalPassword = memberEntity.getPassword(); - final String modifyPasswordMemberURL = MEMBER_URL + "/" + memberId; + final String modifyPasswordMemberURL = MEMBER_URL + "/" + memberEntity.getMemberId(); ModifyPasswordRequest modifyPasswordRequest = ModifyPasswordRequest.builder() .password("modified123") .build(); @@ -193,7 +191,7 @@ void modifyPasswordMemberTest() throws Exception { //then actions.andExpect(status().isOk()); - MemberEntity updatedMember = memberRepository.findById(memberId).get(); + MemberEntity updatedMember = memberRepository.findById(memberEntity.getMemberId()).get(); assertThat(originalPassword).isNotEqualTo(updatedMember.getPassword()); } @@ -203,8 +201,8 @@ void modifyPasswordMemberTest() throws Exception { void deleteMemberTest() throws Exception { //given //회원가입을 한 후 삭제 필드는 null이다. - Long memberId = memberService.signUp(getCreateMemberRequest("test1@naver.com")); - MemberEntity memberEntity = memberRepository.findById(memberId).get(); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + Long memberId = memberEntity.getMemberId(); assertThat(memberEntity.getDeletedAt()).isNull(); String deleteURL = MEMBER_URL + "/" + memberId; @@ -218,18 +216,6 @@ void deleteMemberTest() throws Exception { } - private CreateMemberRequest getCreateMemberRequest(String email) { - String password = "test1234"; - String name = "현수"; - String telNo = "010-1234-1244"; - - CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo - ); - - return createMemberRequest; - } - private CreateSellerRequest getCreateSellerRequest(Long memberId) { String brandName = "나이키"; String bizNo = "102-13-13122"; diff --git a/src/test/java/org/store/clothstar/member/controller/SellerControllerIntegrationTest.java b/src/test/java/org/store/clothstar/member/controller/SellerControllerIntegrationTest.java index ea19cdd9..1c7b2a5a 100644 --- a/src/test/java/org/store/clothstar/member/controller/SellerControllerIntegrationTest.java +++ b/src/test/java/org/store/clothstar/member/controller/SellerControllerIntegrationTest.java @@ -13,8 +13,11 @@ import org.springframework.test.web.servlet.ResultActions; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.CreateSellerRequest; +import org.store.clothstar.member.entity.MemberEntity; +import org.store.clothstar.member.repository.MemberRepository; import org.store.clothstar.member.service.MemberServiceImpl; import org.store.clothstar.member.service.SellerServiceImpl; +import org.store.clothstar.member.util.CreateObject; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -31,11 +34,15 @@ class SellerControllerIntegrationTest { @Autowired private SellerServiceImpl sellerServiceImpl; + @Autowired + private MemberRepository memberRepository; + @Autowired MemberServiceImpl memberServiceImpl; private static final String SELLER_URL = "/v1/sellers"; + MemberEntity memberEntity; private Long memberId; private final String brandName = "나이키"; private final String bizNo = "102-13-13122"; @@ -45,7 +52,8 @@ class SellerControllerIntegrationTest { @Test void getSellerTest() throws Exception { //given - memberId = memberServiceImpl.signUp(getCreateMemberRequest("test1@naver.com")); + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + memberId = memberEntity.getMemberId(); Long sellerId = sellerServiceImpl.sellerSave(memberId, getCreateSellerRequest()); String sellerMemberIdURL = SELLER_URL + "/" + memberId; @@ -65,9 +73,10 @@ private CreateMemberRequest getCreateMemberRequest(String email) { String password = "test1234"; String name = "현수"; String telNo = "010-1234-1244"; + String certifyNum = "123asdf"; CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo + email, password, name, telNo, certifyNum ); return createMemberRequest; diff --git a/src/test/java/org/store/clothstar/member/service/MemberServiceJpaUnitTest.java b/src/test/java/org/store/clothstar/member/service/MemberServiceJpaUnitTest.java index caa61306..536a72e3 100644 --- a/src/test/java/org/store/clothstar/member/service/MemberServiceJpaUnitTest.java +++ b/src/test/java/org/store/clothstar/member/service/MemberServiceJpaUnitTest.java @@ -8,10 +8,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.store.clothstar.member.domain.MemberRole; -import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.ModifyMemberRequest; import org.store.clothstar.member.entity.MemberEntity; import org.store.clothstar.member.repository.MemberRepository; +import org.store.clothstar.member.util.CreateObject; import java.time.LocalDateTime; @@ -35,9 +35,9 @@ public class MemberServiceJpaUnitTest { @BeforeEach public void getMemberId_getAccessToken() { //given && when - memberId = memberServiceImpl.signUp(getCreateMemberRequest()); - memberEntity = memberRepository.findById(memberId).get(); - + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + memberId = memberEntity.getMemberId(); + //then assertThat(memberId).isNotNull(); } @@ -116,22 +116,11 @@ void memberDeleteAtUnitTest() { @Test void signUpValid_idDuplicateCheck() { Throwable exception = assertThrows(IllegalArgumentException.class, () -> { - memberServiceImpl.signUp(getCreateMemberRequest()); + memberServiceImpl.signUp(CreateObject.getCreateMemberRequest()); }); assertThat(exception.getMessage()).isEqualTo("이미 존재하는 아이디 입니다."); } - private CreateMemberRequest getCreateMemberRequest() { - String email = "test3@test.com"; - String password = "testl122"; - String name = "현수"; - String telNo = "010-1234-1245"; - - CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo - ); - return createMemberRequest; - } } \ No newline at end of file diff --git a/src/test/java/org/store/clothstar/member/service/SellerCreateJpaServiceUnitTest.java b/src/test/java/org/store/clothstar/member/service/SellerCreateJpaServiceUnitTest.java index 0af08086..94b7aaaa 100644 --- a/src/test/java/org/store/clothstar/member/service/SellerCreateJpaServiceUnitTest.java +++ b/src/test/java/org/store/clothstar/member/service/SellerCreateJpaServiceUnitTest.java @@ -7,8 +7,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; -import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.CreateSellerRequest; +import org.store.clothstar.member.entity.MemberEntity; +import org.store.clothstar.member.repository.MemberRepository; +import org.store.clothstar.member.util.CreateObject; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -23,6 +25,10 @@ class SellerCreateJpaServiceUnitTest { @Autowired private MemberService memberService; + @Autowired + private MemberRepository memberRepository; + + private MemberEntity memberEntity; private Long memberId; private Long memberId2; private String brandName = "나이키"; @@ -31,8 +37,11 @@ class SellerCreateJpaServiceUnitTest { @DisplayName("회원가입과 판매자 신청을 진행 하고 memberId와 sellerId가 정상적으로 반환되는지 확인한다.") @BeforeEach public void signUp_getMemberId() { - memberId = memberService.signUp(getCreateMemberRequest()); - memberId2 = memberService.signUp(getCreateMemberRequest2()); + memberEntity = memberRepository.save(CreateObject.getCreateMemberRequest("test1@naver.com").toMemberEntity()); + memberId = memberEntity.getMemberId(); + + memberEntity = memberRepository.save(CreateObject.getCreateMemberRequest("test2@naver.com").toMemberEntity()); + memberId2 = memberEntity.getMemberId(); Long sellerId = sellerService.sellerSave(memberId, getCreateSellerRequest()); @@ -87,31 +96,6 @@ void bizNoDuplicateTest() { assertThat(exception.getMessage()).isEqualTo("이미 존재하는 사업자 번호 입니다."); } - private CreateMemberRequest getCreateMemberRequest() { - String email = "test@test.com"; - String password = "testl122"; - String name = "현수"; - String telNo = "010-1234-1245"; - - CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo - ); - - return createMemberRequest; - } - - private CreateMemberRequest getCreateMemberRequest2() { - String email = "test2@test.com"; - String password = "testl122"; - String name = "현수"; - String telNo = "010-1234-1245"; - - CreateMemberRequest createMemberRequest = new CreateMemberRequest( - email, password, name, telNo - ); - - return createMemberRequest; - } private CreateSellerRequest getCreateSellerRequest() { CreateSellerRequest createSellerRequest = new CreateSellerRequest( diff --git a/src/test/java/org/store/clothstar/member/util/CreateObject.java b/src/test/java/org/store/clothstar/member/util/CreateObject.java new file mode 100644 index 00000000..685e2a38 --- /dev/null +++ b/src/test/java/org/store/clothstar/member/util/CreateObject.java @@ -0,0 +1,38 @@ +package org.store.clothstar.member.util; + +import org.store.clothstar.member.dto.request.CreateMemberRequest; +import org.store.clothstar.member.entity.MemberEntity; + +public class CreateObject { + public static CreateMemberRequest getCreateMemberRequest() { + String email = "test3@test.com"; + String password = "testl122"; + String name = "현수"; + String telNo = "010-1234-1245"; + String certifyNum = "asdf123"; + + CreateMemberRequest createMemberRequest = new CreateMemberRequest( + email, password, name, telNo, certifyNum + ); + + return createMemberRequest; + } + + public static CreateMemberRequest getCreateMemberRequest(String email) { + String password = "testl122"; + String name = "현수"; + String telNo = "010-1234-1245"; + String certifyNum = "asdf123"; + + CreateMemberRequest createMemberRequest = new CreateMemberRequest( + email, password, name, telNo, certifyNum + ); + + return createMemberRequest; + } + + + public static MemberEntity getMemberEntityByCreateMemberRequestDTO() { + return getCreateMemberRequest().toMemberEntity(); + } +} From b2c06c1d3a18c1e62df0fe3694fa7e3943bf5d78 Mon Sep 17 00:00:00 2001 From: hyunsu Date: Sat, 6 Jul 2024 05:56:15 +0900 Subject: [PATCH 9/9] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20redis=20=EC=9D=B8=EC=A6=9D=20test=20code=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- .../member/service/MemberServiceImpl.java | 10 ++-- src/main/resources/application.yml | 2 +- .../common/config/JasyptConfigTest.java | 4 +- .../common/mail/MailServiceTest.java | 2 - .../clothstar/common/redis/RedisUtilTest.java | 26 ++++++--- .../MemberAndSellerSignUpIntegrationTest.java | 55 ++++++++++++------- .../MemberControllerValidationTest.java | 21 ++++++- .../clothstar/member/util/CreateObject.java | 11 ++++ src/test/resources/application-test.yml | 6 ++ 10 files changed, 100 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 0a765de9..4208daf5 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ out/ src/main/resources/app.key src/main/resources/app.pub -!**/src/main/generated \ No newline at end of file +/src/main/generated/ \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java index df36d0d0..3618a5d7 100644 --- a/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java +++ b/src/main/java/org/store/clothstar/member/service/MemberServiceImpl.java @@ -99,7 +99,7 @@ public Long signUp(CreateMemberRequest createMemberDTO) { MemberEntity memberEntity = createMemberDTO.toMemberEntity(encodedPassword); //인증코드 확인 - boolean certifyStatus = verifyEmailCode(memberEntity.getEmail(), createMemberDTO.getCertifyNum()); + boolean certifyStatus = verifyEmailCertifyNum(memberEntity.getEmail(), createMemberDTO.getCertifyNum()); if (certifyStatus) { memberEntity = memberRepository.save(memberEntity); } else { @@ -129,12 +129,12 @@ private String sendEmailAuthentication(String toEmail) { return certifyNum; } - public Boolean verifyEmailCode(String email, String certifyNum) { - String codeFoundByEmail = redisUtil.getData(email); - if (codeFoundByEmail == null) { + public Boolean verifyEmailCertifyNum(String email, String certifyNum) { + String certifyNumFoundByRedis = redisUtil.getData(email); + if (certifyNumFoundByRedis == null) { return false; } - return codeFoundByEmail.equals(certifyNum); + return certifyNumFoundByRedis.equals(certifyNum); } } \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 406af5ca..c3629899 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -27,7 +27,7 @@ spring: # Redis data: redis: - host: localhost + host: ENC(GUuFDW7HjE98e7N28Vkb/xoIEgLeOCb5) port: 6379 duration: 600 diff --git a/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java index 5371bf4b..39727bba 100644 --- a/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java +++ b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java @@ -10,8 +10,8 @@ class JasyptConfigTest { @Test void jasypt() { String url = ""; - String username = "nexthope22@gmail.com"; - String password = "pcde pppv pnxa dfmg"; + String username = ""; + String password = ""; System.out.println(jasyptEncoding(url)); System.out.println(jasyptEncoding(username)); diff --git a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java index ded32e15..c9e143f2 100644 --- a/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -1,7 +1,6 @@ package org.store.clothstar.common.mail; import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -10,7 +9,6 @@ @SpringBootTest @ActiveProfiles("test") -@Disabled class MailServiceTest { @Autowired MailService mailService; diff --git a/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java b/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java index 3a2a24c8..ecea53b7 100644 --- a/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java +++ b/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java @@ -1,29 +1,39 @@ package org.store.clothstar.common.redis; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; @SpringBootTest +@ActiveProfiles("test") class RedisUtilTest { @Autowired private RedisUtil redisUtil; - + @DisplayName("redis 데이터가 생성되고 삭제되는지 확인한다.") @Test - public void redisTest() throws Exception { + public void redisCreateAndDeleteTest() throws Exception { + //redis 데이터가 생성됐는지 확인한다. //given - String email = "test@test.com"; - String code = "aaa111"; + String key = "test@test.com"; + String value = "aaa111"; + + //when + redisUtil.setDataExpire(key, value); + + //then + Assertions.assertTrue(redisUtil.existData(key)); + Assertions.assertEquals(redisUtil.getData(key), value); + //redis 데이터가 삭제 됐는지 확인한다. //when - redisUtil.setDataExpire(email, code); + redisUtil.deleteData(key); //then - Assertions.assertTrue(redisUtil.existData("test@test.com")); - Assertions.assertFalse(redisUtil.existData("test1@test.com")); - Assertions.assertEquals(redisUtil.getData(email), "aaa111"); + Assertions.assertFalse(redisUtil.existData(key)); } } \ No newline at end of file diff --git a/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java b/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java index 4dff33e1..cef59b15 100644 --- a/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java +++ b/src/test/java/org/store/clothstar/member/controller/MemberAndSellerSignUpIntegrationTest.java @@ -1,8 +1,6 @@ package org.store.clothstar.member.controller; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -14,11 +12,9 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.transaction.annotation.Transactional; -import org.store.clothstar.common.config.jwt.JwtUtil; +import org.store.clothstar.common.redis.RedisUtil; import org.store.clothstar.member.domain.MemberRole; -import org.store.clothstar.member.dto.request.CreateSellerRequest; -import org.store.clothstar.member.dto.request.ModifyMemberRequest; -import org.store.clothstar.member.dto.request.ModifyPasswordRequest; +import org.store.clothstar.member.dto.request.*; import org.store.clothstar.member.entity.MemberEntity; import org.store.clothstar.member.repository.MemberRepository; import org.store.clothstar.member.util.CreateObject; @@ -41,23 +37,27 @@ class MemberAndSellerSignUpIntegrationTest { private ObjectMapper objectMapper; @Autowired - private JwtUtil jwtUtil; + private MemberRepository memberRepository; @Autowired - private MemberRepository memberRepository; + private RedisUtil redisUtil; private static final String MEMBER_URL = "/v1/members"; private static final String SELLER_URL = "/v1/sellers"; private MemberEntity memberEntity; - @DisplayName("회원가입을 완료한 후 memberId와 accessToken을 받아서 판매자 가입을 신청한 테스트이다.") + @DisplayName("회원가입 통합테스트") @WithMockUser - @Disabled @Test - void signUpAndSellerTest() throws Exception { + void signUpIntegrationTest() throws Exception { //회원가입 통합 테스트 //given - final String requestBody = objectMapper.writeValueAsString(CreateObject.getCreateMemberRequest()); + String email = "test@naver.com"; + String certifyNum = redisUtil.createdCertifyNum(); + redisUtil.createRedisData(email, certifyNum); + + CreateMemberRequest createMemberRequest = CreateObject.getCreateMemberRequest(email, certifyNum); + final String requestBody = objectMapper.writeValueAsString(createMemberRequest); //when ResultActions actions = mockMvc.perform(post(MEMBER_URL) @@ -66,22 +66,39 @@ void signUpAndSellerTest() throws Exception { //then actions.andExpect(status().isCreated()); + } - String responseBody = actions.andReturn().getResponse().getContentAsString(); - JsonNode jsonNode = objectMapper.readTree(responseBody); - Long memberId = jsonNode.get("id").asLong(); - MemberEntity memberEntity = memberRepository.findById(memberId).get(); - String accessToken = jwtUtil.createAccessToken(memberEntity); + @DisplayName("회원가입시 인증번호 전송 통합테스트") + @WithMockUser + @Test + void certifyNumEmailSendTest() throws Exception { + //given + CertifyNumRequest certifyNumRequest = new CertifyNumRequest("test@naver.com"); + final String url = "/v1/members/auth"; + final String requestBody = objectMapper.writeValueAsString(certifyNumRequest); + + //when + ResultActions actions = mockMvc.perform(post(url) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)); - //회원가입해서 받은 memberId로 판매자 신청 테스트 + //then + actions.andExpect(status().isOk()).andDo(print()); + } + + @DisplayName("판매자(Seller) 가입 통합테스트") + @WithMockUser(roles = "SELLER") + @Test + void sellerSignUpIntegrationTest() throws Exception { //given + memberEntity = memberRepository.save(CreateObject.getMemberEntityByCreateMemberRequestDTO()); + Long memberId = memberEntity.getMemberId(); final String sellerUrl = SELLER_URL + "/" + memberId; CreateSellerRequest createSellerRequest = getCreateSellerRequest(memberId); final String sellerRequestBody = objectMapper.writeValueAsString(createSellerRequest); //when ResultActions sellerActions = mockMvc.perform(post(sellerUrl) - .header("Authorization", "Bearer " + accessToken) .contentType(MediaType.APPLICATION_JSON) .content(sellerRequestBody)); diff --git a/src/test/java/org/store/clothstar/member/controller/MemberControllerValidationTest.java b/src/test/java/org/store/clothstar/member/controller/MemberControllerValidationTest.java index c67894ea..0f8ed093 100644 --- a/src/test/java/org/store/clothstar/member/controller/MemberControllerValidationTest.java +++ b/src/test/java/org/store/clothstar/member/controller/MemberControllerValidationTest.java @@ -13,10 +13,14 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.transaction.annotation.Transactional; +import org.store.clothstar.common.error.exception.SignupCertifyNumAuthFailedException; import org.store.clothstar.member.dto.request.CreateMemberRequest; import org.store.clothstar.member.dto.request.ModifyPasswordRequest; import org.store.clothstar.member.repository.MemberRepository; +import org.store.clothstar.member.service.MemberService; +import org.store.clothstar.member.util.CreateObject; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -36,9 +40,24 @@ public class MemberControllerValidationTest { @Autowired MemberRepository memberRepository; + @Autowired + MemberService memberService; + private static final String MEMBER_SIGN_UP_URL = "/v1/members"; - @DisplayName("회원가입시 이메일 양식을 지켜야 한다..") + @DisplayName("회원가입시 인증번호가 틀리면 회원가입이 안돼야 한다.") + @Test + void signUpCertifyNumFailTest() { + //given + CreateMemberRequest createMemberRequest = CreateObject.getCreateMemberRequest(); + + //when & then + Throwable exception = assertThrows(SignupCertifyNumAuthFailedException.class, () -> { + memberService.signUp(createMemberRequest); + }); + } + + @DisplayName("회원가입시 이메일 양식을 지켜야 한다.") @Test void signUp_emailValidationTest() throws Exception { //given diff --git a/src/test/java/org/store/clothstar/member/util/CreateObject.java b/src/test/java/org/store/clothstar/member/util/CreateObject.java index 685e2a38..e723188b 100644 --- a/src/test/java/org/store/clothstar/member/util/CreateObject.java +++ b/src/test/java/org/store/clothstar/member/util/CreateObject.java @@ -31,6 +31,17 @@ public static CreateMemberRequest getCreateMemberRequest(String email) { return createMemberRequest; } + public static CreateMemberRequest getCreateMemberRequest(String email, String certifyNum) { + String password = "testl122"; + String name = "현수"; + String telNo = "010-1234-1245"; + + CreateMemberRequest createMemberRequest = new CreateMemberRequest( + email, password, name, telNo, certifyNum + ); + + return createMemberRequest; + } public static MemberEntity getMemberEntityByCreateMemberRequestDTO() { return getCreateMemberRequest().toMemberEntity(); diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 0c076a70..8882060f 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -20,6 +20,12 @@ spring: auth: true starttls: enable: true + # Redis + data: + redis: + host: ENC(GUuFDW7HjE98e7N28Vkb/xoIEgLeOCb5) + port: 6379 + duration: 600 jpa: hibernate: