diff --git a/.gitignore b/.gitignore index 1fea113a..4208daf5 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/build.gradle b/build.gradle index 29728dc4..d1f7819b 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,12 @@ 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' + + //Redis 의존성 + implementation 'org.springframework.boot:spring-boot-starter-data-redis' } tasks.named('test') { 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/common/error/ErrorCode.java b/src/main/java/org/store/clothstar/common/error/ErrorCode.java index 3ac7a62b..3c4b3096 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 토큰이 만료되었거나 유효하지 않습니다."), + 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/SignupCertifyNumAuthFailedException.java b/src/main/java/org/store/clothstar/common/error/exception/SignupCertifyNumAuthFailedException.java new file mode 100644 index 00000000..35d58fd4 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/error/exception/SignupCertifyNumAuthFailedException.java @@ -0,0 +1,12 @@ +package org.store.clothstar.common.error.exception; + +import org.store.clothstar.common.error.ErrorCode; + +public class SignupCertifyNumAuthFailedException extends RuntimeException { + private final 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/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..53b08264 --- /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 certifyNum) { + Context context = new Context(); + 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/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..1022af2d --- /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.info("전송 메일주소 : {} -> {}", fromAddress, mailSendDTO.getAddress()); + mailSender.send(messagePreparator); + + return true; + } +} diff --git a/src/main/java/org/store/clothstar/common/redis/RedisConfig.java b/src/main/java/org/store/clothstar/common/redis/RedisConfig.java new file mode 100644 index 00000000..431ccb32 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/redis/RedisConfig.java @@ -0,0 +1,21 @@ +package org.store.clothstar.common.redis; + +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/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..aa0472f4 --- /dev/null +++ b/src/main/java/org/store/clothstar/common/redis/RedisUtil.java @@ -0,0 +1,59 @@ +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; + +import java.time.Duration; +import java.util.Random; + +@RequiredArgsConstructor +@Service +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); + } + + public boolean existData(String key) { + return Boolean.TRUE.equals(template.hasKey(key)); + } + + public void setDataExpire(String key, String value) { + ValueOperations valueOperations = template.opsForValue(); + Duration expireDuration = Duration.ofSeconds(duration); + valueOperations.set(key, value, expireDuration); + } + + 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/application/MemberServiceApplication.java b/src/main/java/org/store/clothstar/member/application/MemberServiceApplication.java index 5afe0cd2..4ac4cc8b 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 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 78f0fd4d..14f0fad1 100644 --- a/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java +++ b/src/main/java/org/store/clothstar/member/controller/AuthenticationController.java @@ -12,6 +12,7 @@ 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; @@ -32,7 +33,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 +44,10 @@ public ResponseEntity signup(@Validated @RequestBody CreateMemb public void login(@RequestBody MemberLoginRequest memberLoginRequest) { // 실제 로그인 로직은 Spring Security에서 처리 } + + @Operation(summary = "이메일로 인증번호 전송", description = "기입한 이메일로 인증번호를 전송합니다.") + @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 7994add1..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 @@ -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,8 +24,11 @@ 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() + @NotNull(message = "인증번호를 입력해 주세요") + private String certifyNum; + + public MemberEntity toMemberEntity(String encryptedPassword) { + return MemberEntity.builder() .email(email) .password(encryptedPassword) .name(name) @@ -40,14 +37,13 @@ public Member toMember(String encryptedPassword) { .point(0) .role(MemberRole.USER) .grade(MemberGrade.BRONZE) - .createdAt(LocalDateTime.now()) .build(); } - public MemberEntity toMemberEntity(String encryptedPassword) { + public MemberEntity toMemberEntity() { return MemberEntity.builder() .email(email) - .password(encryptedPassword) + .password(password) .name(name) .telNo(telNo) .totalPaymentPrice(0) 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..1fa8fc47 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 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 9373688c..3618a5d7 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,16 @@ package org.store.clothstar.member.service; 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.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; @@ -22,16 +27,14 @@ */ @Service @Slf4j +@RequiredArgsConstructor @Transactional public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; private final PasswordEncoder passwordEncoder; - - public MemberServiceImpl( - @Qualifier("memberJpaRepository") MemberRepository memberRepository) { - this.memberRepository = memberRepository; - this.passwordEncoder = new BCryptPasswordEncoder(); - } + private final MailContentBuilder mailContentBuilder; + private final MailService mailService; + private final RedisUtil redisUtil; @Override public List findAll() { @@ -94,8 +97,44 @@ public Long signUp(CreateMemberRequest createMemberDTO) { String encodedPassword = passwordEncoder.encode(createMemberDTO.getPassword()); MemberEntity memberEntity = createMemberDTO.toMemberEntity(encodedPassword); - memberEntity = memberRepository.save(memberEntity); + + //인증코드 확인 + boolean certifyStatus = verifyEmailCertifyNum(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 signupCertifyNumEmailSend(String email) { + sendEmailAuthentication(email); + log.info("인증번호 전송 완료, email = {}", email); + } + + private String sendEmailAuthentication(String toEmail) { + String certifyNum = redisUtil.createdCertifyNum(); + String message = mailContentBuilder.build(certifyNum); + MailSendDTO mailSendDTO = new MailSendDTO(toEmail, "clothstar 회원가입 인증 메일 입니다.", message); + + mailService.sendMail(mailSendDTO); + + //메일 전송에 성공하면 redis에 key = email, value = 인증번호를 생성한다. + //지속시간은 10분 + redisUtil.createRedisData(toEmail, certifyNum); + + return certifyNum; + } + + public Boolean verifyEmailCertifyNum(String email, String certifyNum) { + String certifyNumFoundByRedis = redisUtil.getData(email); + if (certifyNumFoundByRedis == null) { + return false; + } + + return certifyNumFoundByRedis.equals(certifyNum); + } +} \ No newline at end of file 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/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-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..c3629899 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,25 @@ spring: - db-dev include: - db + mail: + host: smtp.gmail.com + port: 587 + username: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) + password: ENC(/hOuHdVpOgyzKrlqyayORlsTFpIrwe7RYnfAqXEFzIk=) + properties: + mail: + smtp: + auth: true + starttls: + enable: true + # Redis + data: + redis: + host: ENC(GUuFDW7HjE98e7N28Vkb/xoIEgLeOCb5) + port: 6379 + duration: 600 + +email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) springdoc: default-consumes-media-type: application/json # 소비 미디어 타입 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; diff --git a/src/main/resources/static/js/signup.js b/src/main/resources/static/js/signup.js index c0aeae7f..55cad551 100644 --- a/src/main/resources/static/js/signup.js +++ b/src/main/resources/static/js/signup.js @@ -1,4 +1,30 @@ 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`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: emailValue + }), + }).then((res) => { + if (res.ok) { + alert("인증번호가 전송 되었습니다.") + } + }).catch(() => { + console.log("catch"); + }); + } + }); +} if (createButton) { createButton.addEventListener("click", (event) => { @@ -12,6 +38,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 +51,7 @@ if (createButton) { }).catch(() => { alert("ajax 호출 에러") }); - }) + }); } const emailCheck = () => { diff --git a/src/main/resources/templates/mailTemplate.html b/src/main/resources/templates/mailTemplate.html new file mode 100644 index 00000000..e2c5b804 --- /dev/null +++ b/src/main/resources/templates/mailTemplate.html @@ -0,0 +1,16 @@ + + + +
+
+

인증 코드 메일입니다.

+
+

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

+
+
+

+
+
+
+ + \ No newline at end of file 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/config/JasyptConfigTest.java b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java index 345c72f9..39727bba 100644 --- a/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java +++ b/src/test/java/org/store/clothstar/common/config/JasyptConfigTest.java @@ -12,7 +12,7 @@ void jasypt() { String url = ""; String username = ""; String password = ""; - + 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/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 new file mode 100644 index 00000000..c9e143f2 --- /dev/null +++ b/src/test/java/org/store/clothstar/common/mail/MailServiceTest.java @@ -0,0 +1,32 @@ +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 = "https://www.naver.com/"; + String message = mailContentBuilder.build(link); + MailSendDTO mailSendDTO = new MailSendDTO("test@test.com", "test", message); + + //when + Boolean success = mailService.sendMail(mailSendDTO); + + //then + Assertions.assertThat(success).isTrue(); + } +} \ No newline at end of file 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..ecea53b7 --- /dev/null +++ b/src/test/java/org/store/clothstar/common/redis/RedisUtilTest.java @@ -0,0 +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 redisCreateAndDeleteTest() throws Exception { + //redis 데이터가 생성됐는지 확인한다. + //given + 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.deleteData(key); + + //then + Assertions.assertFalse(redisUtil.existData(key)); + } +} \ No newline at end of file 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..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,6 +1,5 @@ package org.store.clothstar.member.controller; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,15 +12,12 @@ 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.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.dto.request.*; 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.*; @@ -40,25 +36,27 @@ class MemberAndSellerSignUpIntegrationTest { @Autowired private ObjectMapper objectMapper; - @Autowired - private JwtUtil jwtUtil; - @Autowired private MemberRepository memberRepository; @Autowired - private MemberService memberService; + 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 @Test - void signUpAndSellerTest() throws Exception { + void signUpIntegrationTest() throws Exception { //회원가입 통합 테스트 //given - CreateMemberRequest createMemberRequest = getCreateMemberRequest("test@naver.com"); + 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 @@ -68,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)); @@ -96,9 +111,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 +130,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 +147,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 +164,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 +192,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 +208,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 +218,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 +233,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/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/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..e723188b --- /dev/null +++ b/src/test/java/org/store/clothstar/member/util/CreateObject.java @@ -0,0 +1,49 @@ +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 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 3883c060..8882060f 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -9,6 +9,23 @@ 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 + # Redis + data: + redis: + host: ENC(GUuFDW7HjE98e7N28Vkb/xoIEgLeOCb5) + port: 6379 + duration: 600 jpa: hibernate: @@ -26,3 +43,6 @@ jwt: secret_key: Y2xvdGhzaG9wcGluZ21hbGxjbG90aHN0YXJjbG90aHNob3BwaW5nbWFsbGNsb3Roc3RhcmNsb3Roc2hvcHBpbmdtYWxsY2xvdGhzdGFyY2xvdGhzaG9wcGluZ21hbGxjbG90aHN0YXIK accessTokenValidTimeMillis: 120000 refreshTokenValidTimeMillis: 1200000 + +email.send: ENC(kGXTSlfxUWNbRoGuBwNRTJBETjMz04AChYMrwDeY3Cs=) +