From 4c86bfecfc8e1df497837cf6c72b3774e8c32d7f Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Tue, 26 Mar 2024 16:20:53 +0900 Subject: [PATCH 1/9] =?UTF-8?q?Feat:=20Member=20Service=20Test=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlanIT/common/response/ErrorCode.java | 4 +- .../PlanIT/common/util/RedisUtil.java | 14 +- .../PlanIT/config/EmailConfig.java | 2 +- .../PlanIT/config/SecurityConfig.java | 6 +- .../program/controller/ProgramController.java | 3 +- .../user/controller/EmailController.java | 6 +- .../employee/request/TrainerRequestDto.java | 7 + .../MemberChangePasswordRequestDto.java | 8 + .../member/request/MemberEditRequestDto.java | 9 + .../request/MemberSignInRequestDto.java | 7 + .../request/MemberSignUpRequestDto.java | 11 + .../PlanIT/domain/user/entity/Member.java | 2 +- .../domain/user/service/EmailService.java | 4 +- .../user/service/MemberServiceImpl.java | 25 +- src/main/resources/application-prod.yml | 2 +- src/main/resources/application.yml | 6 +- .../user/service/MemberServiceTest.java | 466 +++++++++++++++++- 17 files changed, 551 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java index 28cdbf4..cb39253 100644 --- a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java +++ b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java @@ -11,16 +11,18 @@ public enum ErrorCode { ALREADY_REFUNDED_PROGRAM(400, "이미 환불된 프로그램입니다."), ALREADY_APPROVE_PROGRAM(400, "이미 등록된 프로그램입니다."), ALREADY_EXIST_EMAIL(400, "이미 존재하는 이메일입니다."), + NO_EXIST_EMAIL(400, "이메일을 입력해주세요."), + NO_EXIST_PASSWORD(400, "비밀번호를 입력해주세요."), INVALID_PASSWORD(400, "비밀번호가 틀렸습니다."), INVALID_EMAIL_AUTH(400, "인증번호가 틀렸습니다."), NOT_PT(400, "PT이용권이 아닙니다."), NOT_YOUR_TRAINER(400, "예약 가능한 트레이너가 아닙니다."), ALREADY_RESERVATION(400, "이미 예약 되어있습니다."), + SAME_PASSWORD(400, "변경 비밀번호가 같습니다."), //401 INVALID_ACCESS_TOKEN(401, "ACCESS TOKEN 오류"), INVALID_REFRESH_TOKEN(401, "REFRESH TOKEN 오류"), - NO_AUTHORITY(401, "권한이 없습니다."), //404 Error Not found. diff --git a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java index b078526..4cb009d 100644 --- a/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java +++ b/src/main/java/com/sideProject/PlanIT/common/util/RedisUtil.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; @@ -13,10 +14,10 @@ @RequiredArgsConstructor public class RedisUtil { - @Value("${email.redis-timeLimit}") + @Value("${spring.email.redis-timeLimit}") private Long emailExpire; - @Value("${jwt.refresh-token-expire}") + @Value("${spring.jwt.refresh-token-expire}") private Long refreshExpire; private final RedisTemplate redisTemplate; @@ -30,7 +31,7 @@ public void setRefreshToken(String refreshToken, Long member_id) { ValueOperations valueOperations = redisTemplate.opsForValue(); redisTemplate.delete(refreshToken); - valueOperations.set(refreshToken, member_id.toString(), refreshExpire); + valueOperations.set(refreshToken, member_id.toString(), Duration.ofMillis(refreshExpire)); } public String getData(String key) { @@ -55,4 +56,11 @@ public void deleteByValue(String value) { } }); } + + public void deleteAll() { + redisTemplate.execute((RedisCallback) connection -> { + connection.serverCommands().flushDb(); + return null; + }); + } } diff --git a/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java index d3af22a..f7c8a17 100644 --- a/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/EmailConfig.java @@ -10,7 +10,7 @@ @Configuration public class EmailConfig { - @Value("${email.app-key}") + @Value("${spring.email.app-key}") private String appKey; @Bean public JavaMailSender mailSender() { diff --git a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java index e72a4e9..888df81 100644 --- a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java @@ -59,10 +59,10 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .exceptionHandling((exceptionHandling) -> exceptionHandling.authenticationEntryPoint(jwtAuthenticationEntryPoint)) .authorizeHttpRequests((authorizeRequests) -> authorizeRequests - .requestMatchers("/member/signin", "/member/signup", "member/refresh").permitAll() + .requestMatchers("/member/signin", "/member/signup", "member/refresh", "/email/**").permitAll() .requestMatchers("/admin/**").hasAnyAuthority("ADMIN") - .anyRequest().authenticated() -// .anyRequest().permitAll() +// .anyRequest().authenticated() + .anyRequest().permitAll() ) .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java index a058878..79cbe36 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java @@ -2,8 +2,8 @@ import com.sideProject.PlanIT.common.response.ApiResponse; import com.sideProject.PlanIT.domain.program.dto.request.RegistrationRequest; -import com.sideProject.PlanIT.domain.program.dto.response.ProgramResponse; import com.sideProject.PlanIT.domain.program.dto.response.FindRegistrationResponse; +import com.sideProject.PlanIT.domain.program.dto.response.ProgramResponse; import com.sideProject.PlanIT.domain.program.entity.enums.ProgramSearchStatus; import com.sideProject.PlanIT.domain.program.entity.enums.RegistrationSearchStatus; import com.sideProject.PlanIT.domain.program.service.ProgramService; @@ -44,7 +44,6 @@ public ApiResponse> find( ); } - //어드민이 유저 id로 검색 @GetMapping("/{id}") public ApiResponse find( diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java index 77c5fc6..ee97cd2 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java @@ -6,18 +6,18 @@ import com.sideProject.PlanIT.domain.user.service.EmailService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor +@RequestMapping("/email") public class EmailController { private final EmailService emailService; - @PostMapping("/email") + @PostMapping public ApiResponse mailSend(@RequestBody @Valid EmailSendReqeustDto emailSendReqeustDto) { return ApiResponse.ok(emailService.joinEmail(emailSendReqeustDto.getEmail())); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/employee/request/TrainerRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/employee/request/TrainerRequestDto.java index 44e069f..e5c2189 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/dto/employee/request/TrainerRequestDto.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/employee/request/TrainerRequestDto.java @@ -1,6 +1,7 @@ package com.sideProject.PlanIT.domain.user.dto.employee.request; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,4 +10,10 @@ public class TrainerRequestDto { private String career; private String trainerMessage; + + @Builder + public TrainerRequestDto(String career, String trainerMessage) { + this.career = career; + this.trainerMessage = trainerMessage; + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberChangePasswordRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberChangePasswordRequestDto.java index 036e5ea..b3b76d3 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberChangePasswordRequestDto.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberChangePasswordRequestDto.java @@ -1,6 +1,7 @@ package com.sideProject.PlanIT.domain.user.dto.member.request; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -10,4 +11,11 @@ public class MemberChangePasswordRequestDto { private String currentPassword; private String newPassword; private String newPasswordCheck; + + @Builder + public MemberChangePasswordRequestDto(String currentPassword, String newPassword, String newPasswordCheck) { + this.currentPassword = currentPassword; + this.newPassword = newPassword; + this.newPasswordCheck = newPasswordCheck; + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberEditRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberEditRequestDto.java index 167f3d5..2955541 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberEditRequestDto.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberEditRequestDto.java @@ -1,6 +1,7 @@ package com.sideProject.PlanIT.domain.user.dto.member.request; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,4 +14,12 @@ public class MemberEditRequestDto { private String phone_number; private LocalDate birth; private String address; + + @Builder + public MemberEditRequestDto(String name, String phone_number, LocalDate birth, String address) { + this.name = name; + this.phone_number = phone_number; + this.birth = birth; + this.address = address; + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignInRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignInRequestDto.java index 0570a41..f485b0d 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignInRequestDto.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignInRequestDto.java @@ -1,6 +1,7 @@ package com.sideProject.PlanIT.domain.user.dto.member.request; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,4 +10,10 @@ public class MemberSignInRequestDto { private String email; private String password; + + @Builder + public MemberSignInRequestDto(String email, String password) { + this.email = email; + this.password = password; + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignUpRequestDto.java b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignUpRequestDto.java index ebe866a..41b9df3 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignUpRequestDto.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/dto/member/request/MemberSignUpRequestDto.java @@ -1,6 +1,7 @@ package com.sideProject.PlanIT.domain.user.dto.member.request; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,4 +16,14 @@ public class MemberSignUpRequestDto { private String phone_number; private LocalDate birth; private String address; + + @Builder + public MemberSignUpRequestDto(String email, String password, String name, String phone_number, LocalDate birth, String address) { + this.email = email; + this.password = password; + this.name = name; + this.phone_number = phone_number; + this.birth = birth; + this.address = address; + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/entity/Member.java b/src/main/java/com/sideProject/PlanIT/domain/user/entity/Member.java index 4a7634d..1621a00 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/entity/Member.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/entity/Member.java @@ -22,7 +22,7 @@ public class Member { @Column(name = "email", nullable = false, unique = true) private String email; - @Column + @Column(nullable = false) private String password; @Column diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java index d7d2772..0e72903 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java @@ -7,13 +7,10 @@ import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; -import java.util.Objects; -import java.util.Optional; import java.util.Random; @Service @@ -29,6 +26,7 @@ public String validEmail(EmailValidationRequestDto emailValidationRequestDto) { if (!emailValidationRequestDto.getValidCode().equals(redisUtil.getData(emailValidationRequestDto.getEmail()))) { throw new CustomException(ErrorCode.INVALID_EMAIL_AUTH); } + redisUtil.deleteData(emailValidationRequestDto.getEmail()); return "인증 완료"; } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java index c810ca3..52fa919 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java @@ -13,17 +13,18 @@ import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignUpRequestDto; import com.sideProject.PlanIT.domain.user.dto.member.response.JwtResponseDto; import com.sideProject.PlanIT.domain.user.dto.member.response.MemberResponseDto; -import com.sideProject.PlanIT.domain.user.entity.enums.MemberRole; import com.sideProject.PlanIT.domain.user.entity.Employee; import com.sideProject.PlanIT.domain.user.entity.Member; +import com.sideProject.PlanIT.domain.user.entity.enums.MemberRole; import com.sideProject.PlanIT.domain.user.repository.EmployeeRepository; import com.sideProject.PlanIT.domain.user.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +//todo: transactional 공부 후 추가 @Service @RequiredArgsConstructor @@ -38,9 +39,11 @@ public class MemberServiceImpl implements MemberService { public Member signUp(MemberSignUpRequestDto memberSignUpRequestDto) { memberRepository.findByEmail(memberSignUpRequestDto.getEmail()) .ifPresent( user1 -> { - throw new CustomException("이메일이 이미 존재합니다.", ErrorCode.ALREADY_EXIST_EMAIL); + throw new CustomException(ErrorCode.ALREADY_EXIST_EMAIL); }); - + if (memberSignUpRequestDto.getPassword() == null) { + throw new CustomException(ErrorCode.NO_EXIST_PASSWORD); + } String encryptedPassword = passwordEncoder.encode(memberSignUpRequestDto.getPassword()); return memberRepository.save(Member.builder() .email(memberSignUpRequestDto.getEmail()) @@ -75,7 +78,7 @@ public String deleteMember(Long member_id) { @Override public String editMember(Long member_id, MemberEditRequestDto memberEditRequestDto) { Member memberToEdit = memberRepository.findById(member_id).orElseThrow(() -> - new IllegalArgumentException("no extist id")); + new CustomException(ErrorCode.MEMBER_NOT_FOUND)); memberToEdit.update(memberEditRequestDto); @@ -87,14 +90,18 @@ public String editMember(Long member_id, MemberEditRequestDto memberEditRequestD @Override public String changePassword(Long member_id, MemberChangePasswordRequestDto memberChangePasswordRequestDto) { Member memberToChangePassword = memberRepository.findById(member_id).orElseThrow(() -> - new IllegalArgumentException("no exist id")); + new CustomException(ErrorCode.MEMBER_NOT_FOUND)); if (!passwordEncoder.matches(memberChangePasswordRequestDto.getCurrentPassword(), memberToChangePassword.getPassword())) { - throw new CustomException("현재 비밀번호가 일치하지 않습니다.", ErrorCode.INVALID_PASSWORD); + throw new CustomException(ErrorCode.INVALID_PASSWORD); } if (!memberChangePasswordRequestDto.getNewPassword().equals(memberChangePasswordRequestDto.getNewPasswordCheck())) { - throw new CustomException("변경할 비밀번호가 일치하지 않습니다.", ErrorCode.INVALID_PASSWORD); + throw new CustomException(ErrorCode.INVALID_PASSWORD); + } + + if (passwordEncoder.matches(memberChangePasswordRequestDto.getNewPassword(), memberToChangePassword.getPassword())) { + throw new CustomException(ErrorCode.SAME_PASSWORD); } String encryptedNewPassword = passwordEncoder.encode(memberChangePasswordRequestDto.getNewPassword()); @@ -160,7 +167,7 @@ public Page findAllEmployees(Pageable pageable) { @Override public String grantEmployeeAuth(Long member_id, TrainerRequestDto trainerRequestDto) { Member memberToEmployee = memberRepository.findById(member_id).orElseThrow(() -> - new IllegalArgumentException("no exist id")); + new CustomException(ErrorCode.MEMBER_NOT_FOUND)); memberToEmployee.grantEmployeeAuth(); memberRepository.save(memberToEmployee); diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index d8f493c..a098fb9 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -9,7 +9,7 @@ spring: jwt: secret-key: ${SECRET_KEY} - access-token-expire: 432000 + access-token-expire: 50000 refresh-token-expire: 1209600000 datasource: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 37ddf43..ee17906 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -43,9 +43,9 @@ spring: login-uri: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount? redirect-uri: http://localhost:8080/login/oauth2/code/google -email: - app-key: ${EMAIL_APP_KEY} - redis-timeLimit: 300000 + email: + app-key: ${EMAIL_APP_KEY} + redis-timeLimit: 300000 # 환경변수 설정 # - DB USER_NAME, PASSWORD diff --git a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java index c47389f..8d0cd1e 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java @@ -1,11 +1,475 @@ package com.sideProject.PlanIT.domain.user.service; +import com.sideProject.PlanIT.common.response.CustomException; +import com.sideProject.PlanIT.common.util.JwtTokenProvider; +import com.sideProject.PlanIT.common.util.JwtUtil; +import com.sideProject.PlanIT.common.util.RedisUtil; +import com.sideProject.PlanIT.domain.user.dto.employee.request.TrainerRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.MemberChangePasswordRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.MemberEditRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignInRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignUpRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.response.JwtResponseDto; +import com.sideProject.PlanIT.domain.user.dto.member.response.MemberResponseDto; +import com.sideProject.PlanIT.domain.user.entity.Employee; +import com.sideProject.PlanIT.domain.user.entity.Member; +import com.sideProject.PlanIT.domain.user.entity.enums.MemberRole; +import com.sideProject.PlanIT.domain.user.repository.EmployeeRepository; +import com.sideProject.PlanIT.domain.user.repository.MemberRepository; import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.context.ActiveProfiles; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + @Slf4j @SpringBootTest -@ActiveProfiles("dev") +@ActiveProfiles("prod") public class MemberServiceTest { + + @Autowired + MemberRepository memberRepository; + + @Autowired + EmployeeRepository employeeRepository; + + @Autowired + MemberService memberService; + + @Autowired + PasswordEncoder passwordEncoder; + + @Autowired + JwtTokenProvider jwtTokenProvider; + + @Autowired + JwtUtil jwtUtil; + + @Autowired + RedisUtil redisUtil; + + @AfterEach + void tearDown() { + employeeRepository.deleteAllInBatch(); + memberRepository.deleteAllInBatch(); + redisUtil.deleteAll(); + } + + private Member initMember(String name, String password) { + Member member = Member.builder() + .name(name) + .email(name + "@naver.com") + .password(password) + .birth(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .phone_number("010-0000-0000") + .address("서울") + .role(MemberRole.MEMBER) + .build(); + + return memberRepository.save(member); + } + + @Nested + @DisplayName("signUpTest") + class signUpTest { + + @DisplayName("모든 정보를 받아 회원 가입을 한다.") + @Test + void signUp() { + // given + // when + // then + // given + MemberSignUpRequestDto memberSignUpRequestDto = MemberSignUpRequestDto.builder() + .email("test1@naver.com") + .password("test1234") + .name("test") + .phone_number("123456789") + .birth(LocalDate.of(2024, 03, 25)) + .address("서울") + .build(); + + // when + Member member = memberService.signUp(memberSignUpRequestDto); + + // then + assertThat(member).isNotNull(); + assertThat(member.getEmail()).isEqualTo("test1@naver.com"); + assertThat(member.getName()).isEqualTo("test"); + assertThat(member.getPhone_number()).isEqualTo("123456789"); + assertThat(member.getBirth()).isEqualTo("2024-03-25"); + assertThat(member.getAddress()).isEqualTo("서울"); + assertThat(passwordEncoder.matches("test1234", member.getPassword())).isTrue(); + } + + @DisplayName("이메일이 이미 존재하면 오류가 발생한다") + @Test + void signUp2() { + // given + MemberSignUpRequestDto memberSignUpRequestDto1 = MemberSignUpRequestDto.builder() + .email("test1@naver.com") + .password("test1234") + .name("test1") + .build(); + + MemberSignUpRequestDto memberSignUpRequestDto2 = MemberSignUpRequestDto.builder() + .email("test1@naver.com") + .password("test5678") + .name("test2") + .build(); + + memberService.signUp(memberSignUpRequestDto1); + + // when, then + assertThatThrownBy(() -> memberService.signUp(memberSignUpRequestDto2)) + .isInstanceOf(CustomException.class) + .hasMessage("이미 존재하는 이메일입니다."); + } + + @DisplayName("비밀번호를 입력하지 않으면 오류가 발생한다") + @Test + void signUp3() { + // given + MemberSignUpRequestDto memberSignUpRequestDto1 = MemberSignUpRequestDto.builder() + .email("test1@naver.com") + .name("test1") + .build(); + + // when, then + assertThatThrownBy(() -> memberService.signUp(memberSignUpRequestDto1)) + .isInstanceOf(CustomException.class) + .hasMessage("비밀번호를 입력해주세요."); + } + } + + @Nested + @DisplayName("signInTest") + class signInTest { + + @DisplayName("로그인을 하고 토큰을 받는다.") + @Test + void signIn() { + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() + .email("test1@naver.com") + .password("test1234") + .build(); + + // when + JwtResponseDto jwtResponseDto = memberService.memberValidation(memberSignInRequestDto); + + // then + assertThat(jwtResponseDto.getAccessToken()).isNotNull(); + assertThat(jwtResponseDto.getRefreshToken()).isNotNull(); + assertThat(jwtUtil.getMemberIdFromToken(jwtResponseDto.getAccessToken())).isEqualTo(memberRepository.findByEmail("test1@naver.com").get().getId()); + assertThat(jwtUtil.getMemberRoleFromToken(jwtResponseDto.getAccessToken())).isEqualTo(memberRepository.findByEmail("test1@naver.com").get().getRole().toString()); + assertThat(redisUtil.getData(jwtResponseDto.getRefreshToken())).isEqualTo(memberRepository.findByEmail("test1@naver.com").get().getId().toString()); + } + + @DisplayName("이메일이 없으면 오류가 발생한다") + @Test + void signIn2() { + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() + .email("test2@naver.com") + .password("test1234") + .build(); + + // then + assertThatThrownBy(() -> memberService.memberValidation(memberSignInRequestDto)) + .isInstanceOf(CustomException.class) + .hasMessage("회원을 찾을 수 없습니다"); + } + + @DisplayName("비밀번호가 틀리면 오류가 발생한다") + @Test + void signIn3() { + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() + .email("test1@naver.com") + .password("test12345") + .build(); + + // then + assertThatThrownBy(() -> memberService.memberValidation(memberSignInRequestDto)) + .isInstanceOf(CustomException.class) + .hasMessage("비밀번호가 틀렸습니다."); + } + } + + @Nested + @DisplayName("deleteMemberTest") + class deleteMemberTest { + + @DisplayName("member_id로 member를 삭제한다") + @Test + void deleteMember() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + memberService.deleteMember(memberRepository.findByEmail("test1@naver.com").get().getId()); + + // then + assertThat(memberRepository.findByEmail("test1").isPresent()).isFalse(); + } + } + + @Nested + @DisplayName("editMemberTest") + class editMemberTest { + + @DisplayName("사용자 정보를 수정한다") + @Test + void editMember() { + + // given + memberRepository.save(Member.builder() + .email("test1@naver.com") + .password("test1234") + .name("test1") + .phone_number("010-0000-0000") + .birth(LocalDate.of(2024, 12, 31)) + .address("서울") + .role(MemberRole.MEMBER) + .build()); + MemberEditRequestDto memberEditRequestDto = MemberEditRequestDto.builder() + .name("test2") + .phone_number("010-1234-5678") + .birth(LocalDate.of(2001, 1, 1)) + .address("경기") + .build(); + + // when + memberService.editMember(memberRepository.findByEmail("test1@naver.com").get().getId(), memberEditRequestDto); + + // then + Member member = memberRepository.findByEmail("test1@naver.com").get(); + assertThat(member.getName()).isEqualTo("test2"); + assertThat(member.getPhone_number()).isEqualTo("010-1234-5678"); + assertThat(member.getBirth()).isEqualTo("2001-01-01"); + assertThat(member.getAddress()).isEqualTo("경기"); + } + } + + @Nested + @DisplayName("changePasswordTest") + class changePasswordTest { + + @DisplayName("비밀번호를 변경한다") + @Test + void changePassword() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() + .currentPassword("test1234") + .newPassword("test5678") + .newPasswordCheck("test5678") + .build(); + memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto); + + // then + assertThat(passwordEncoder.matches("test5678", memberRepository.findByEmail("test1@naver.com").get().getPassword())).isTrue(); + } + + @DisplayName("현재 비밀번호가 틀리면 오류가 발생한다") + @Test + void changePassword2() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() + .currentPassword("test5678") + .newPassword("test5678") + .newPasswordCheck("test5678") + .build(); + + // then + assertThatThrownBy(() -> memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto)) + .isInstanceOf(CustomException.class) + .hasMessage("비밀번호가 틀렸습니다."); + } + + @DisplayName("변경할 비밀번호와 변경할 비밀번호 재입력이 다르면 오류가 발생한다") + @Test + void changePassword3() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() + .currentPassword("test1234") + .newPassword("test5678") + .newPasswordCheck("test0000") + .build(); + + // then + assertThatThrownBy(() -> memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto)) + .isInstanceOf(CustomException.class) + .hasMessage("비밀번호가 틀렸습니다."); + } + + @DisplayName("기존 비밀번호와 변경할 비밀번호가 같으면 오류가 발생한다") + @Test + void changePassword4() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() + .currentPassword("test1234") + .newPassword("test1234") + .newPasswordCheck("test1234") + .build(); + + // then + assertThatThrownBy(() -> memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto)) + .isInstanceOf(CustomException.class) + .hasMessage("변경 비밀번호가 같습니다."); + } + } + + @Nested + @DisplayName("findMemberTest") + class findMemberTest { + + @DisplayName("member_id로 멤버를 조회한다") + @Test + void findMember() { + + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + + // when + MemberResponseDto memberResponseDto = memberService.findMember(memberRepository.findByEmail("test1@naver.com").get().getId()); + + // then + assertThat(memberResponseDto.getName()).isEqualTo("test1"); + assertThat(memberResponseDto.getAddress()).isEqualTo("서울"); + assertThat(memberResponseDto.getBirth()).isEqualTo("2000-01-01"); + assertThat(memberResponseDto.getPhone_number()).isEqualTo("010-0000-0000"); + assertThat(memberResponseDto.getRole()).isEqualTo(MemberRole.MEMBER); + } + + @DisplayName("member_id로 조회한 멤버가 트레이너면 트레이너 정보와 함께 조회한다") + @Test + void findMemberTrainer() { + + // given + memberRepository.save(Member.builder() + .email("test1@naver.com") + .password("test1234") + .name("test1") + .birth(LocalDate.of(2000, 1, 1)) + .address("서울") + .phone_number("010-0000-0000") + .role(MemberRole.TRAINER) + .build()); + employeeRepository.save(Employee.builder() + .member(memberRepository.findByEmail("test1@naver.com").get()) + .career("P1Y2M3D") + .trainerMessage("test trainer message") + .build()); + + // when + MemberResponseDto memberResponseDto = memberService.findMember(memberRepository.findByEmail("test1@naver.com").get().getId()); + + // then + assertThat(memberResponseDto.getEmail()).isEqualTo("test1@naver.com"); + assertThat(memberResponseDto.getName()).isEqualTo("test1"); + assertThat(memberResponseDto.getAddress()).isEqualTo("서울"); + assertThat(memberResponseDto.getPhone_number()).isEqualTo("010-0000-0000"); + assertThat(memberResponseDto.getBirth()).isEqualTo("2000-01-01"); + assertThat(memberResponseDto.getRole()).isEqualTo(MemberRole.TRAINER); + assertThat(memberResponseDto.getTrainerInfo().getCareer()).isEqualTo("P1Y2M3D"); + assertThat(memberResponseDto.getTrainerInfo().getTrainerMessage()).isEqualTo("test trainer message"); + } + + } + + @Nested + @DisplayName("signOutTest") + class signOutTest { + + @DisplayName("로그아웃을 하고 refresh token을 삭제합니다") + @Test + void signOut() { + + // given + Member member = memberRepository.save(initMember("test1", "test1234")); + String refreshToken = jwtTokenProvider.createRefreshToken(member); + + // when + memberService.signOut(memberRepository.findByEmail("test1@naver.com").get().getId()); + + // then + assertThat(redisUtil.isExist(refreshToken)).isFalse(); + } + } + + @Nested + @DisplayName("findTest") + class findTest { + + } + + @Nested + @DisplayName("findAllMembersTest") + class findAllMembers { + + } + + @Nested + @DisplayName("findAllEmployeesTest") + class findAllEmployees { + + } + + @Nested + @DisplayName("grantEmployeeTest") + class grantEmployeeTest { + + @DisplayName("회원에게 트레이너 권한을 부여한다") + @Test + void grantEmployee() { + // given + memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + TrainerRequestDto trainerRequestDto = TrainerRequestDto.builder() + .career("P1Y2M3D") + .trainerMessage("test trainer message") + .build(); + + // when + memberService.grantEmployeeAuth(memberRepository.findByEmail("test1@naver.com").get().getId(), trainerRequestDto); + + // then + assertThat(memberRepository.findByEmail("test1@naver.com").get().getRole()).isEqualTo(MemberRole.TRAINER); + } + } } From d8298641850f06b0877faf4b7aa6beae06e09d86 Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Tue, 26 Mar 2024 20:58:48 +0900 Subject: [PATCH 2/9] =?UTF-8?q?Feat:=20Member=20Test=20Code=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlanIT/config/SecurityConfig.java | 4 +- .../domain/user/service/MemberService.java | 1 - .../user/service/MemberServiceImpl.java | 8 +- .../user/service/MemberServiceTest.java | 136 +++++++++++++++--- 4 files changed, 116 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java index 888df81..12c6ca0 100644 --- a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java @@ -61,8 +61,8 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .authorizeHttpRequests((authorizeRequests) -> authorizeRequests .requestMatchers("/member/signin", "/member/signup", "member/refresh", "/email/**").permitAll() .requestMatchers("/admin/**").hasAnyAuthority("ADMIN") -// .anyRequest().authenticated() - .anyRequest().permitAll() + .anyRequest().authenticated() +// .anyRequest().permitAll() ) .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberService.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberService.java index 763f891..40eb418 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberService.java @@ -23,7 +23,6 @@ public interface MemberService { MemberResponseDto findMember(Long member_id); String signOut(Long member_id); Page find(MemberSearchOption option, Pageable pageable); - Page findAllMembers(Pageable pageable); Page findAllEmployees(Pageable pageable); String grantEmployeeAuth(Long member_id, TrainerRequestDto trainerRequestDto); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java index 52fa919..bd06ee4 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/MemberServiceImpl.java @@ -108,7 +108,7 @@ public String changePassword(Long member_id, MemberChangePasswordRequestDto memb memberToChangePassword.changePassword(encryptedNewPassword); memberRepository.save(memberToChangePassword); - return "비밀 번호 변경 완료"; + return "비밀번호 변경 완료"; } @Override @@ -152,12 +152,6 @@ public Page find(MemberSearchOption option, Pageable pageable return members.map(member -> MemberResponseDto.of(member, null)); } - @Override - public Page findAllMembers(Pageable pageable) { - Page members = memberRepository.findByRole(MemberRole.MEMBER,pageable); - return members.map(member -> MemberResponseDto.of(member, null)); - } - @Override public Page findAllEmployees(Pageable pageable) { Page employees = employeeRepository.findAll(pageable); diff --git a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java index 8d0cd1e..c62e2cd 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java @@ -4,7 +4,9 @@ import com.sideProject.PlanIT.common.util.JwtTokenProvider; import com.sideProject.PlanIT.common.util.JwtUtil; import com.sideProject.PlanIT.common.util.RedisUtil; +import com.sideProject.PlanIT.domain.user.controller.enums.MemberSearchOption; import com.sideProject.PlanIT.domain.user.dto.employee.request.TrainerRequestDto; +import com.sideProject.PlanIT.domain.user.dto.employee.response.TrainerResponseDto; import com.sideProject.PlanIT.domain.user.dto.member.request.MemberChangePasswordRequestDto; import com.sideProject.PlanIT.domain.user.dto.member.request.MemberEditRequestDto; import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignInRequestDto; @@ -23,6 +25,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.context.ActiveProfiles; @@ -65,7 +70,7 @@ void tearDown() { redisUtil.deleteAll(); } - private Member initMember(String name, String password) { + private Member initMember(String name, String password, MemberRole memberRole) { Member member = Member.builder() .name(name) .email(name + "@naver.com") @@ -73,7 +78,7 @@ private Member initMember(String name, String password) { .birth(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) .phone_number("010-0000-0000") .address("서울") - .role(MemberRole.MEMBER) + .role(memberRole) .build(); return memberRepository.save(member); @@ -160,7 +165,7 @@ class signInTest { @Test void signIn() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() .email("test1@naver.com") @@ -182,7 +187,7 @@ void signIn() { @Test void signIn2() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() @@ -200,7 +205,7 @@ void signIn2() { @Test void signIn3() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberSignInRequestDto memberSignInRequestDto = MemberSignInRequestDto.builder() @@ -224,13 +229,14 @@ class deleteMemberTest { void deleteMember() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when - memberService.deleteMember(memberRepository.findByEmail("test1@naver.com").get().getId()); + String result = memberService.deleteMember(memberRepository.findByEmail("test1@naver.com").get().getId()); // then assertThat(memberRepository.findByEmail("test1").isPresent()).isFalse(); + assertThat(result).isEqualTo("삭제 완료"); } } @@ -260,7 +266,7 @@ void editMember() { .build(); // when - memberService.editMember(memberRepository.findByEmail("test1@naver.com").get().getId(), memberEditRequestDto); + String result = memberService.editMember(memberRepository.findByEmail("test1@naver.com").get().getId(), memberEditRequestDto); // then Member member = memberRepository.findByEmail("test1@naver.com").get(); @@ -268,6 +274,7 @@ void editMember() { assertThat(member.getPhone_number()).isEqualTo("010-1234-5678"); assertThat(member.getBirth()).isEqualTo("2001-01-01"); assertThat(member.getAddress()).isEqualTo("경기"); + assertThat(result).isEqualTo("수정 완료"); } } @@ -280,7 +287,7 @@ class changePasswordTest { void changePassword() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() @@ -288,10 +295,11 @@ void changePassword() { .newPassword("test5678") .newPasswordCheck("test5678") .build(); - memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto); + String result = memberService.changePassword(memberRepository.findByEmail("test1@naver.com").get().getId(), memberChangePasswordRequestDto); // then assertThat(passwordEncoder.matches("test5678", memberRepository.findByEmail("test1@naver.com").get().getPassword())).isTrue(); + assertThat(result).isEqualTo("비밀번호 변경 완료"); } @DisplayName("현재 비밀번호가 틀리면 오류가 발생한다") @@ -299,7 +307,7 @@ void changePassword() { void changePassword2() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() @@ -319,7 +327,7 @@ void changePassword2() { void changePassword3() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() @@ -339,7 +347,7 @@ void changePassword3() { void changePassword4() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberChangePasswordRequestDto memberChangePasswordRequestDto = MemberChangePasswordRequestDto.builder() @@ -364,7 +372,7 @@ class findMemberTest { void findMember() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); // when MemberResponseDto memberResponseDto = memberService.findMember(memberRepository.findByEmail("test1@naver.com").get().getId()); @@ -417,19 +425,20 @@ void findMemberTrainer() { @DisplayName("signOutTest") class signOutTest { - @DisplayName("로그아웃을 하고 refresh token을 삭제합니다") + @DisplayName("로그아웃을 하고 refresh token을 삭제한다") @Test void signOut() { // given - Member member = memberRepository.save(initMember("test1", "test1234")); + Member member = initMember("test1", "test1234", MemberRole.MEMBER); String refreshToken = jwtTokenProvider.createRefreshToken(member); // when - memberService.signOut(memberRepository.findByEmail("test1@naver.com").get().getId()); + String result = memberService.signOut(memberRepository.findByEmail("test1@naver.com").get().getId()); // then assertThat(redisUtil.isExist(refreshToken)).isFalse(); + assertThat(result).isEqualTo("로그아웃 성공"); } } @@ -437,18 +446,99 @@ void signOut() { @DisplayName("findTest") class findTest { - } + @DisplayName("모든 사용자를 조회한다.") + @Test + void find() { - @Nested - @DisplayName("findAllMembersTest") - class findAllMembers { + // given + initMember("test1", "test1234", MemberRole.MEMBER); + initMember("test2", "test1234", MemberRole.MEMBER); + initMember("test3", "test1234", MemberRole.MEMBER); + initMember("test4", "test1234", MemberRole.TRAINER); + initMember("test5", "test1234", MemberRole.TRAINER); + + // when + Pageable pageable = PageRequest.of(1, 3); + Page result = memberService.find(MemberSearchOption.ALL, pageable); + + // then + assertThat(result.getTotalElements()).isEqualTo(5); + assertThat(result.getTotalPages()).isEqualTo(2); + assertThat(result.getContent().size()).isEqualTo(2); + } + + @DisplayName("모든 회원를 조회한다.") + @Test + void find2() { + + // given + initMember("test1", "test1234", MemberRole.MEMBER); + initMember("test2", "test1234", MemberRole.MEMBER); + initMember("test3", "test1234", MemberRole.MEMBER); + initMember("test4", "test1234", MemberRole.TRAINER); + initMember("test5", "test1234", MemberRole.TRAINER); + + // when + Pageable pageable = PageRequest.of(0, 3); + Page result = memberService.find(MemberSearchOption.MEMBER, pageable); + + // then + assertThat(result.getTotalElements()).isEqualTo(3); + assertThat(result.getTotalPages()).isEqualTo(1); + assertThat(result.getContent().size()).isEqualTo(3); + } + + @DisplayName("모든 트레이너를 조회한다.") + @Test + void find3() { + // given + initMember("test1", "test1234", MemberRole.MEMBER); + initMember("test2", "test1234", MemberRole.MEMBER); + initMember("test3", "test1234", MemberRole.MEMBER); + initMember("test4", "test1234", MemberRole.TRAINER); + initMember("test5", "test1234", MemberRole.TRAINER); + + // when + Pageable pageable = PageRequest.of(0, 3); + Page result = memberService.find(MemberSearchOption.TRAINER, pageable); + + // then + assertThat(result.getTotalElements()).isEqualTo(2); + assertThat(result.getTotalPages()).isEqualTo(1); + assertThat(result.getContent().size()).isEqualTo(2); + } } @Nested @DisplayName("findAllEmployeesTest") - class findAllEmployees { + class findAllEmployeesTest { + + @DisplayName("전체 트레이너를 조회합니다.") + @Test + void findAllEmployees() { + + // given + employeeRepository.save(Employee.builder() + .member(initMember("test1", "test1234", MemberRole.TRAINER)) + .career("P1Y2M3D") + .trainerMessage("test trainer messsage") + .build()); + employeeRepository.save(Employee.builder() + .member(initMember("test2", "test1234", MemberRole.TRAINER)) + .career("P1Y2M3D") + .trainerMessage("test trainer messsage") + .build()); + + // when + Pageable pageable = PageRequest.of(0, 2); + Page result = memberService.findAllEmployees(pageable); + // then + assertThat(result.getTotalElements()).isEqualTo(2); + assertThat(result.getTotalPages()).isEqualTo(1); + assertThat(result.getContent().size()).isEqualTo(2); + } } @Nested @@ -459,7 +549,7 @@ class grantEmployeeTest { @Test void grantEmployee() { // given - memberRepository.save(initMember("test1", passwordEncoder.encode("test1234"))); + initMember("test1", passwordEncoder.encode("test1234"), MemberRole.MEMBER); TrainerRequestDto trainerRequestDto = TrainerRequestDto.builder() .career("P1Y2M3D") .trainerMessage("test trainer message") From f16902521369f8d023c9b51385e5af6a89f6829e Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Tue, 26 Mar 2024 21:46:10 +0900 Subject: [PATCH 3/9] =?UTF-8?q?Fix:=20API=20End=20Point=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlanIT/config/SecurityConfig.java | 2 +- .../file/controller/FileController.java | 4 ++- .../user/controller/AuthController.java | 23 -------------- .../user/controller/EmailController.java | 30 ------------------- .../user/controller/MemberController.java | 26 ++++++++++++---- .../controller/SocialLoginController.java | 2 ++ .../user/service/MemberServiceTest.java | 2 ++ 7 files changed, 29 insertions(+), 60 deletions(-) delete mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/controller/AuthController.java delete mode 100644 src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java diff --git a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java index 12c6ca0..e87d5e3 100644 --- a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java @@ -59,7 +59,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .exceptionHandling((exceptionHandling) -> exceptionHandling.authenticationEntryPoint(jwtAuthenticationEntryPoint)) .authorizeHttpRequests((authorizeRequests) -> authorizeRequests - .requestMatchers("/member/signin", "/member/signup", "member/refresh", "/email/**").permitAll() + .requestMatchers("/member/signin", "/member/signup", "/member/refresh", "/member/email/**").permitAll() .requestMatchers("/admin/**").hasAnyAuthority("ADMIN") .anyRequest().authenticated() // .anyRequest().permitAll() diff --git a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java index 2336f3d..4383650 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/file/controller/FileController.java @@ -10,12 +10,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; @RestController @RequiredArgsConstructor +@RequestMapping("/file") public class FileController { private final FileHandler fileHandler; @@ -33,7 +35,7 @@ public ResponseEntity loadImage(@PathVariable String image_name) { } } - @GetMapping("/file/{file_name}") + @GetMapping("/{file_name}") public ResponseEntity loadFile(@PathVariable String file_name) { try { byte[] fileBytes = fileHandler.loadFile(file_name); diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/AuthController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/AuthController.java deleted file mode 100644 index c806511..0000000 --- a/src/main/java/com/sideProject/PlanIT/domain/user/controller/AuthController.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.sideProject.PlanIT.domain.user.controller; - -import com.sideProject.PlanIT.common.response.ApiResponse; -import com.sideProject.PlanIT.domain.user.dto.member.response.JwtResponseDto; -import com.sideProject.PlanIT.domain.user.service.AuthService; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/member") -public class AuthController { - - private final AuthService authService; - - @GetMapping("/refresh") - public ApiResponse refreshAccessToken(@RequestHeader("Authorization") String authorizationHeader) { - return ApiResponse.ok(authService.refreshAccessToken(authorizationHeader)); - } -} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java deleted file mode 100644 index ee97cd2..0000000 --- a/src/main/java/com/sideProject/PlanIT/domain/user/controller/EmailController.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.sideProject.PlanIT.domain.user.controller; - -import com.sideProject.PlanIT.common.response.ApiResponse; -import com.sideProject.PlanIT.domain.user.dto.member.request.EmailSendReqeustDto; -import com.sideProject.PlanIT.domain.user.dto.member.request.EmailValidationRequestDto; -import com.sideProject.PlanIT.domain.user.service.EmailService; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/email") -public class EmailController { - private final EmailService emailService; - - @PostMapping - public ApiResponse mailSend(@RequestBody @Valid EmailSendReqeustDto emailSendReqeustDto) { - return ApiResponse.ok(emailService.joinEmail(emailSendReqeustDto.getEmail())); - } - - @PostMapping("/check") - public ApiResponse mailValidation(@RequestBody @Valid EmailValidationRequestDto emailValidationRequestDto) { - return ApiResponse.ok(emailService.validEmail(emailValidationRequestDto)); - } - -} diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/MemberController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/MemberController.java index 7140421..1e20bfe 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/controller/MemberController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/controller/MemberController.java @@ -2,13 +2,13 @@ import com.sideProject.PlanIT.common.response.ApiResponse; import com.sideProject.PlanIT.domain.user.dto.employee.response.TrainerResponseDto; -import com.sideProject.PlanIT.domain.user.dto.member.request.MemberChangePasswordRequestDto; -import com.sideProject.PlanIT.domain.user.dto.member.request.MemberEditRequestDto; -import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignInRequestDto; -import com.sideProject.PlanIT.domain.user.dto.member.request.MemberSignUpRequestDto; +import com.sideProject.PlanIT.domain.user.dto.member.request.*; import com.sideProject.PlanIT.domain.user.dto.member.response.JwtResponseDto; import com.sideProject.PlanIT.domain.user.dto.member.response.MemberResponseDto; +import com.sideProject.PlanIT.domain.user.service.AuthService; +import com.sideProject.PlanIT.domain.user.service.EmailService; import com.sideProject.PlanIT.domain.user.service.MemberService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; -import java.util.List; @RestController @Slf4j @@ -26,17 +25,34 @@ public class MemberController { private final MemberService memberService; + private final EmailService emailService; + private final AuthService authService; @PostMapping("/signup") public ApiResponse signUp(@RequestBody MemberSignUpRequestDto memberSignUpRequestDto) { return ApiResponse.ok(memberService.signUp(memberSignUpRequestDto).getId()); } + @PostMapping("/email") + public ApiResponse mailSend(@RequestBody @Valid EmailSendReqeustDto emailSendReqeustDto) { + return ApiResponse.ok(emailService.joinEmail(emailSendReqeustDto.getEmail())); + } + + @PostMapping("/email/check") + public ApiResponse mailValidation(@RequestBody @Valid EmailValidationRequestDto emailValidationRequestDto) { + return ApiResponse.ok(emailService.validEmail(emailValidationRequestDto)); + } + @PostMapping("/signin") public ApiResponse signIn(@RequestBody MemberSignInRequestDto memberSignInRequestDto) { return ApiResponse.ok(memberService.memberValidation(memberSignInRequestDto)); } + @GetMapping("/refresh") + public ApiResponse refreshAccessToken(@RequestHeader("Authorization") String authorizationHeader) { + return ApiResponse.ok(authService.refreshAccessToken(authorizationHeader)); + } + @DeleteMapping public ApiResponse deleteMember(Principal principal) { return ApiResponse.ok(memberService.deleteMember(Long.parseLong(principal.getName()))); diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/controller/SocialLoginController.java b/src/main/java/com/sideProject/PlanIT/domain/user/controller/SocialLoginController.java index c8dd342..83ac824 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/controller/SocialLoginController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/controller/SocialLoginController.java @@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; + +//todo: 프론트와 협의 후 수정 및 api 엔드 포인트 변경 @RestController @RequiredArgsConstructor @RequestMapping("/login") diff --git a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java index c62e2cd..5bfdad9 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/user/service/MemberServiceTest.java @@ -37,6 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; + +//todo: pagealbe 관련 개수 외에 실제 데이터 검증 @Slf4j @SpringBootTest @ActiveProfiles("prod") From 322370cb4edba5a06a1c688de4c295ec5de27780 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Tue, 26 Mar 2024 23:21:12 +0900 Subject: [PATCH 4/9] test : reservationEntity Test --- .../PlanIT/common/response/ErrorCode.java | 1 + .../PlanIT/config/SecurityConfig.java | 1 - .../controller/ProgramAdminController.java | 3 + .../PlanIT/domain/program/entity/Program.java | 4 + .../program/service/ProgramServiceImpl.java | 6 +- .../controller/ReservationController.java | 8 +- .../reservation/entity/Reservation.java | 32 +++- .../service/ReservationService.java | 4 +- .../service/ReservationServiceImpl.java | 23 +-- .../reservation/entity/ReservationTest.java | 138 ++++++++++++++++++ .../service/ReservationServiceTest.java | 76 ++++++---- 11 files changed, 239 insertions(+), 57 deletions(-) create mode 100644 src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java diff --git a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java index cb39253..f4bfeeb 100644 --- a/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java +++ b/src/main/java/com/sideProject/PlanIT/common/response/ErrorCode.java @@ -19,6 +19,7 @@ public enum ErrorCode { NOT_YOUR_TRAINER(400, "예약 가능한 트레이너가 아닙니다."), ALREADY_RESERVATION(400, "이미 예약 되어있습니다."), SAME_PASSWORD(400, "변경 비밀번호가 같습니다."), + INVALID_RESERVATION_TIME(400, "예약 가능한 시간이 아닙니다."), //401 INVALID_ACCESS_TOKEN(401, "ACCESS TOKEN 오류"), diff --git a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java index 12c6ca0..10e1b4c 100644 --- a/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java +++ b/src/main/java/com/sideProject/PlanIT/config/SecurityConfig.java @@ -62,7 +62,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .requestMatchers("/member/signin", "/member/signup", "member/refresh", "/email/**").permitAll() .requestMatchers("/admin/**").hasAnyAuthority("ADMIN") .anyRequest().authenticated() -// .anyRequest().permitAll() ) .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java index 13494d1..083ba5a 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java @@ -13,6 +13,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.security.Principal; @@ -34,6 +36,7 @@ public ApiResponse> find( @PageableDefault(size = 10) Pageable pageable, Principal principal) { //todo : spring security 개발 후 토큰에서 userID를 전달해 줘야함. + Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication(); Long id = Long.parseLong(principal.getName()); return ApiResponse.ok( diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/entity/Program.java b/src/main/java/com/sideProject/PlanIT/domain/program/entity/Program.java index 8a42d8d..64c0a05 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/entity/Program.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/entity/Program.java @@ -124,6 +124,10 @@ public void resumeProgram(LocalDate resumeAt,LocalDate endAt) { } public void reservation() { + if(this.product.getType() != ProductType.PT) { + throw new CustomException("program " + this.id + " 은 PT권이 아닙니다.", ErrorCode.NOT_PT); + } + if(this.remainedNumber == 0) { throw new CustomException(this.id + "의 남은 횟수가 없습니다", ErrorCode.EMPLOYEE_NOT_FOUND); }else if(this.remainedNumber ==1 ){ diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java index 4282f6f..f731710 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java @@ -318,7 +318,7 @@ public ProgramResponse findByProgramId(long programId, long userId) { ); Program programs = programRepository.findById(programId).orElseThrow(() -> - new CustomException("존재하지 않는 회원입니다.", ErrorCode.MEMBER_NOT_FOUND) + new CustomException(programId + "은 존재하지 않는 프로그램입니다.", ErrorCode.PROGRAM_NOT_FOUND) ); if(member.getRole().equals(MemberRole.TRAINER)) { @@ -402,10 +402,6 @@ private Page findAndConvertRegistrations(RegistrationS registrations = findRegistrationByUser(member, option, pageable); } - if (registrations.isEmpty()) { - throw new CustomException("조건을 만족하는 Registration이 없습니다.", ErrorCode.REGISTRATION_NOT_FOUND); - } - return registrations.map(FindRegistrationResponse::of); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java index 22f1c87..83e81f6 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java @@ -47,7 +47,8 @@ public ApiResponse reservation( reservationService.reservation( reservationId, Long.valueOf(principal.getName()), - request.getProgramId() + request.getProgramId(), + now ) ); } @@ -92,10 +93,13 @@ public ApiResponse cancelReservation( @PathVariable("reservationId") Long reservationId, Principal principal ) { + LocalDateTime now = LocalDateTime.now(); + return ApiResponse.ok( reservationService.cancel( Long.valueOf(principal.getName()), - reservationId + reservationId, + now ) ); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/entity/Reservation.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/entity/Reservation.java index 2309458..70a3e8a 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/entity/Reservation.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/entity/Reservation.java @@ -1,5 +1,7 @@ package com.sideProject.PlanIT.domain.reservation.entity; +import com.sideProject.PlanIT.common.response.CustomException; +import com.sideProject.PlanIT.common.response.ErrorCode; import com.sideProject.PlanIT.domain.program.entity.Program; import com.sideProject.PlanIT.domain.reservation.entity.ENUM.ReservationStatus; import com.sideProject.PlanIT.domain.user.entity.Employee; @@ -19,6 +21,8 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter public class Reservation { + private static final int RESERVATION_THRESHOLD_MINUTES = 10; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") @@ -56,16 +60,40 @@ public Reservation( this.status = status; this.employee = employee; } + public void reservation(Program program, Member member, LocalDateTime now) { + ensureReservationIsPossible(now); - public void reservation(Program program, Member member) { this.member = member; this.program = program; this.status = ReservationStatus.RESERVED; } - public void cancel() { + public void cancel(LocalDateTime now) { + ensureCancellationIsPossible(now); + this.program = null; this.member = null; this.status = ReservationStatus.POSSIBLE; } + + private void ensureReservationIsPossible(LocalDateTime now) { + if (status != ReservationStatus.POSSIBLE) { + throw new CustomException("예약 " + id + "은 예약할 수 없습니다.", ErrorCode.ALREADY_RESERVATION); + } + + if (isPastReservationThreshold(now)) { + throw new CustomException("예약 " + id + "은 예약 가능 시간이 지났습니다.", ErrorCode.INVALID_RESERVATION_TIME); + } + } + + private void ensureCancellationIsPossible(LocalDateTime now) { + if (isPastReservationThreshold(now)) { + throw new CustomException("예약 " + id + "은 예약 취소시간이 지났습니다.", ErrorCode.INVALID_RESERVATION_TIME); + } + } + + private boolean isPastReservationThreshold(LocalDateTime now) { + return now.isAfter(reservedTime.minusMinutes(RESERVATION_THRESHOLD_MINUTES)); + } + } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java index 7ba5c75..6e6f81c 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java @@ -9,8 +9,8 @@ public interface ReservationService { String changeAvailability(List times, Long userId); - String reservation(Long reservationId, Long userId, Long programId); + String reservation(Long reservationId, Long userId, Long programId, LocalDateTime now); Map> findReservationForWeekByMember(LocalDate day, Long id); Map> findReservationForWeekByEmployee(LocalDate day, Long id); - String cancel(Long userId, Long reservationId); + String cancel(Long userId, Long reservationId, LocalDateTime now); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java index 841f302..dd4580a 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java @@ -82,10 +82,9 @@ public String changeAvailability(List reservedTimes, Long userId) return "ok"; } - //todo: 현재 시간에 따라 예약 가능 여부 체크 @Override @Transactional - public String reservation(Long reservationId, Long userId, Long programId) { + public String reservation(Long reservationId, Long userId, Long programId, LocalDateTime now) { Member member = memberRepository.findById(userId).orElseThrow(() -> new CustomException("존재하지 않는 유저입니다.", ErrorCode.MEMBER_NOT_FOUND) ); @@ -96,25 +95,17 @@ public String reservation(Long reservationId, Long userId, Long programId) { new CustomException(reservationId + "는 존재하지 않는 않는 예약입니다.", ErrorCode.RESERVATION_NOT_FOUND) ); - //todo : entity 역할로 넘기기 - if(reservation.getStatus() != ReservationStatus.POSSIBLE) { - throw new CustomException("예약 " + reservationId + "은 예약할 수 없습니다.", ErrorCode.NOT_YOUR_TRAINER); - } - - if(program.getProduct().getType() != ProductType.PT) { - throw new CustomException("program " + programId + " 은 PT권이 아닙니다.", ErrorCode.NOT_PT); - } - if(!Objects.equals(program.getEmployee().getId(), reservation.getEmployee().getId())) { throw new CustomException("유저 " + userId + "은 해당 트레이너에 예약할 수 없습니다.", ErrorCode.NOT_YOUR_TRAINER); } //프로그램 상태 변경 program.reservation(); - programRepository.save(program); //프로그램 예약 - reservation.reservation(program,member); + reservation.reservation(program,member,now); + + programRepository.save(program); reservationRepository.save(reservation); return "ok"; @@ -174,11 +165,9 @@ private LocalDateTime calEndOfWeek(LocalDate date) { return date.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).atTime(LocalTime.MAX); } - - //todo: 취소 불가 시간 @Override @Transactional - public String cancel(Long userId, Long reservationId) { + public String cancel(Long userId, Long reservationId, LocalDateTime now) { Reservation reservation = reservationRepository.findById(reservationId).orElseThrow(() -> new CustomException("예약 " + reservationId + "은 없는 예약입니다.",ErrorCode.RESERVATION_NOT_FOUND) ); @@ -193,7 +182,7 @@ public String cancel(Long userId, Long reservationId) { programRepository.save(program); //예약 취소 - reservation.cancel(); + reservation.cancel(now); reservationRepository.save(reservation); return "ok"; diff --git a/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java b/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java new file mode 100644 index 0000000..5d73a29 --- /dev/null +++ b/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java @@ -0,0 +1,138 @@ +package com.sideProject.PlanIT.domain.reservation.entity; + +import com.sideProject.PlanIT.common.response.CustomException; +import com.sideProject.PlanIT.domain.product.entity.Product; +import com.sideProject.PlanIT.domain.product.entity.enums.ProductType; +import com.sideProject.PlanIT.domain.program.entity.Program; +import com.sideProject.PlanIT.domain.reservation.entity.ENUM.ReservationStatus; +import com.sideProject.PlanIT.domain.user.entity.Employee; +import com.sideProject.PlanIT.domain.user.entity.Member; +import com.sideProject.PlanIT.domain.user.entity.enums.MemberRole; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Profile; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Period; +import java.time.format.DateTimeFormatter; + +import static com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus.IN_PROGRESS; +import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@Profile("dev") +class ReservationTest { + + private Product initProduct(String name, Period period, int number, ProductType type) { + return Product.builder() + .name(name) + .period(period) + .number(number) + .price(30000) + .type(type) + .build(); + } + + private Member initMember(String name, MemberRole role) { + return Member.builder() + .name(name) + .email(name + "test.com") + .password("test123") + .birth(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .phone_number("010-0000-0000") + .role(role) + .build(); + + + } + + private Employee initTrainer(String name) { + Member member = initMember(name, MemberRole.TRAINER); + + return Employee.builder() + .member(member) + .build(); + } + @DisplayName("예약") + @Test + void reservationTest(){ + //given + Member member = initMember("test",MemberRole.MEMBER); + Employee trainer = initTrainer("trainer"); + Program program = Program.builder() + .build(); + + LocalDateTime reservationTime = LocalDateTime.of(2021, 1, 10, 10, 0, 0); + Reservation reservation = Reservation.builder() + .reservedTime(reservationTime) + .employee(trainer) + .status(ReservationStatus.POSSIBLE) + .classTime(LocalTime.of(1,0)) + .build(); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 10, 9, 49, 59); + //when + reservation.reservation(program,member,reservationTime1); + + //then + assertThat(reservation.getStatus()).isEqualTo(ReservationStatus.RESERVED); + assertThat(reservation.getMember()).isEqualTo(member); + } + + @DisplayName("예약 가능 시간이 지나서 예약을 하면 예외가 발생한다") + @Test + void reservationTest2(){ + //given + Member member = initMember("test",MemberRole.MEMBER); + Employee trainer = initTrainer("trainer"); + Program program = Program.builder() + .build(); + + LocalDateTime reservationTime = LocalDateTime.of(2021, 1, 10, 10, 0, 0); + Reservation reservation = Reservation.builder() + .reservedTime(reservationTime) + .employee(trainer) + .status(ReservationStatus.POSSIBLE) + .classTime(LocalTime.of(1,0)) + .build(); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 10, 9, 50, 50); + //when + + //then + assertThatThrownBy(() -> reservation.reservation(program,member,reservationTime1)) + .isInstanceOf(CustomException.class) + .hasMessage("예약 null은 예약 가능 시간이 지났습니다."); + } + + @DisplayName("예약 되어있으면 예외가 발생한다.") + @Test + void reservationTest3(){ + //given + Member member = initMember("test",MemberRole.MEMBER); + Employee trainer = initTrainer("trainer"); + Program program = Program.builder() + .build(); + + LocalDateTime reservationTime = LocalDateTime.of(2021, 1, 10, 10, 0, 0); + Reservation reservation = Reservation.builder() + .reservedTime(reservationTime) + .employee(trainer) + .status(ReservationStatus.RESERVED) + .classTime(LocalTime.of(1,0)) + .build(); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 10, 9, 50, 50); + //when + + //then + assertThatThrownBy(() -> reservation.reservation(program,member,reservationTime1)) + .isInstanceOf(CustomException.class) + .hasMessage("예약 null은 예약할 수 없습니다."); + } + +} \ No newline at end of file diff --git a/src/test/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceTest.java b/src/test/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceTest.java index 9e61b40..1a9b43b 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceTest.java @@ -265,8 +265,9 @@ void reservationTest(){ .classTime(LocalTime.of(1,0)) .build(); reservationRepository.save(reservation); + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 9, 10, 0, 0); //when - String result = reservationService.reservation(reservation.getId(), member1.getId(), program.getId()); + String result = reservationService.reservation(reservation.getId(), member1.getId(), program.getId(),reservationTime1); List reservation1 = reservationRepository.findAll(); //then @@ -323,8 +324,10 @@ void reservationTestMinusRemainNum(){ .classTime(LocalTime.of(1,0)) .build(); reservationRepository.save(reservation); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 9, 10, 0, 0); //when - String result = reservationService.reservation(reservation.getId(), member1.getId(), program.getId()); + String result = reservationService.reservation(reservation.getId(), member1.getId(), program.getId(),reservationTime1); List reservation1 = reservationRepository.findAll(); //then @@ -382,8 +385,10 @@ void reservationTest2(){ .classTime(LocalTime.of(1,0)) .build(); reservationRepository.save(reservation); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 9, 10, 0, 0); //when //then - assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId())) + assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId(),reservationTime1)) .isInstanceOf(CustomException.class) .hasMessage("유저 " + member1.getId()+ "은 해당 트레이너에 예약할 수 없습니다."); } @@ -427,8 +432,10 @@ void reservationTest3(){ .classTime(LocalTime.of(1,0)) .build(); reservationRepository.save(reservation); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 9, 10, 0, 0); //when //then - assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId())) + assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId(),reservationTime1)) .isInstanceOf(CustomException.class) .hasMessage("program " + program.getId()+ " 은 PT권이 아닙니다."); } @@ -457,6 +464,7 @@ void reservationTest4(){ Program program = Program.builder() .registration(saveRegistration) .product(saveRegistration.getProduct()) + .remainedNumber(product.getNumber()) .member(saveRegistration.getMember()) .employee(trainer) .status(IN_PROGRESS) @@ -469,14 +477,16 @@ void reservationTest4(){ Reservation reservation = Reservation.builder() .reservedTime(reservationTime) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); - reservation.reservation(program,member1); + + LocalDateTime reservationTime1 = LocalDateTime.of(2021, 1, 9, 10, 0, 0); + reservation.reservation(program,member1,reservationTime1); Reservation reservation1 = reservationRepository.save(reservation); //when //then - assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId())) + assertThatThrownBy(() -> reservationService.reservation(reservation.getId(), member1.getId(), program.getId(),reservationTime1)) .isInstanceOf(CustomException.class) .hasMessage("예약 " + reservation1.getId() + "은 예약할 수 없습니다."); } @@ -522,7 +532,7 @@ void findReservationByMemberTest(){ Reservation reservation1 = Reservation.builder() .reservedTime(reservationTime1) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); @@ -530,7 +540,7 @@ void findReservationByMemberTest(){ Reservation reservation2 = Reservation.builder() .reservedTime(reservationTime2) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); @@ -538,13 +548,15 @@ void findReservationByMemberTest(){ Reservation reservation3 = Reservation.builder() .reservedTime(reservationTime3) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); - reservation1.reservation(program1,member1); - reservation2.reservation(program1,member1); - reservation3.reservation(program1,member1); + LocalDateTime reservationTime = LocalDateTime.of(2024, 3, 16, 10, 0, 0); + + reservation1.reservation(program1,member1,reservationTime); + reservation2.reservation(program1,member1,reservationTime); + reservation3.reservation(program1,member1,reservationTime); LocalDate today = LocalDate.of(2024, 3, 19); LocalDate today2 = LocalDate.of(2024, 3, 15); @@ -614,7 +626,7 @@ void findReservationByEmployeeTest(){ Reservation reservation1 = Reservation.builder() .reservedTime(reservationTime1) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); @@ -622,7 +634,7 @@ void findReservationByEmployeeTest(){ Reservation reservation2 = Reservation.builder() .reservedTime(reservationTime2) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); @@ -630,13 +642,15 @@ void findReservationByEmployeeTest(){ Reservation reservation3 = Reservation.builder() .reservedTime(reservationTime3) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); - reservation1.reservation(program1,member1); - reservation2.reservation(program1,member1); - reservation3.reservation(program1,member1); + LocalDateTime reservationTime = LocalDateTime.of(2024, 3, 16, 10, 0, 0); + + reservation1.reservation(program1,member1,reservationTime); + reservation2.reservation(program1,member1,reservationTime); + reservation3.reservation(program1,member1,reservationTime); LocalDate today = LocalDate.of(2024, 3, 19); LocalDate today2 = LocalDate.of(2024, 3, 15); @@ -704,7 +718,7 @@ void findEmptyReservation(){ Reservation reservation1 = Reservation.builder() .reservedTime(reservationTime1) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); @@ -712,12 +726,14 @@ void findEmptyReservation(){ Reservation reservation2 = Reservation.builder() .reservedTime(reservationTime2) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); - reservation1.reservation(program1,member1); - reservation2.reservation(program1,member1); + LocalDateTime reservationTime = LocalDateTime.of(2024, 3, 17, 10, 0, 0); + + reservation1.reservation(program1,member1,reservationTime); + reservation2.reservation(program1,member1,reservationTime); LocalDate today = LocalDate.of(2024, 3, 19); LocalDate today2 = LocalDate.of(2024, 3, 15); @@ -750,9 +766,9 @@ void findEmptyReservation(){ @Nested @DisplayName("CancelTest") class CancelTest { - @DisplayName("") + @DisplayName("예약된 예약을 취소할 수 있다.") @Test - void test(){ + void cancel(){ //given Period periodOfTenDays = Period.ofMonths(0); Product product = initProduct("PT 30회권", periodOfTenDays,30,ProductType.PT); @@ -783,18 +799,22 @@ void test(){ Program program1 = programRepository.save(program); LocalDateTime reservationTime1 = LocalDateTime.of(2024, 3, 18, 10, 0, 0); + Reservation reservation1 = Reservation.builder() .reservedTime(reservationTime1) .employee(trainer) - .status(ReservationStatus.RESERVED) + .status(ReservationStatus.POSSIBLE) .classTime(LocalTime.of(1,0)) .build(); - reservation1.reservation(program1,member1); + LocalDateTime reservationTime2 = LocalDateTime.of(2024, 3, 17, 10, 0, 0); + reservation1.reservation(program1,member1,reservationTime2); + + LocalDateTime cancelTime = LocalDateTime.of(2024, 3, 16, 10, 30, 0); Reservation reservation = reservationRepository.save(reservation1); //when - String result = reservationService.cancel(reservation.getMember().getId(),reservation.getId()); + String result = reservationService.cancel(reservation.getMember().getId(),reservation.getId(),cancelTime); Reservation resultReservation = reservationRepository.findById(reservation.getId()).orElseThrow(); Program resultProgram = programRepository.findById(reservation.getProgram().getId()).orElseThrow(); From 8c470eb35a0adb4b9258f446d4727b5e724a7f04 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Tue, 26 Mar 2024 23:30:35 +0900 Subject: [PATCH 5/9] test : reservationEntity cancel Test --- .../reservation/entity/ReservationTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java b/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java index 5d73a29..361370f 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/reservation/entity/ReservationTest.java @@ -135,4 +135,55 @@ void reservationTest3(){ .hasMessage("예약 null은 예약할 수 없습니다."); } + @DisplayName("예약을 취소할 수 있다.") + @Test + void cancelTes1(){ + //given + Member member = initMember("test",MemberRole.MEMBER); + Employee trainer = initTrainer("trainer"); + Program program = Program.builder() + .build(); + + LocalDateTime now = LocalDateTime.now(); + Reservation reservation = Reservation.builder() + .reservedTime(now) + .employee(trainer) + .status(ReservationStatus.RESERVED) + .classTime(LocalTime.of(1,0)) + .build(); + + LocalDateTime reservationTime = now.minusMinutes(10); + //when + reservation.cancel(reservationTime); + + //then + assertThat(reservation.getStatus()).isEqualTo(ReservationStatus.POSSIBLE); + assertThat(reservation.getMember()).isEqualTo(null); + } + + @DisplayName("예약 취소 시간이 예약 시간 10분 이내이면 예외가 발생한다.") + @Test + void cancelTest2(){ + //given + Member member = initMember("test",MemberRole.MEMBER); + Employee trainer = initTrainer("trainer"); + Program program = Program.builder() + .build(); + + LocalDateTime now = LocalDateTime.now(); + Reservation reservation = Reservation.builder() + .reservedTime(now) + .employee(trainer) + .status(ReservationStatus.RESERVED) + .classTime(LocalTime.of(1,0)) + .build(); + + LocalDateTime reservationTime = now.minusMinutes(9); + //when//then + + assertThatThrownBy(() -> reservation.cancel(reservationTime)) + .isInstanceOf(CustomException.class) + .hasMessage("예약 null은 예약 취소시간이 지났습니다."); + } + } \ No newline at end of file From 54e76f73fc61f58b793d3cd14a032217de1524a7 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Wed, 27 Mar 2024 18:33:04 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix=20:=20=ED=8A=B9=EC=A0=95=20=ED=8A=B8?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EB=84=88=EB=A1=9C=20=EC=98=88=EC=95=BD=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=ED=95=B4=EB=8B=B9=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=EB=A7=8C=20=EA=B2=80=EC=83=89=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20#108?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 2 +- .../reservation/service/ReservationService.java | 2 +- .../service/ReservationServiceImpl.java | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java index 83e81f6..f05cb3c 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/controller/ReservationController.java @@ -72,7 +72,7 @@ public ApiResponse>> findReservation( } @GetMapping("/trainer/{employeeId}") - public ApiResponse>> findReservationByEmployee( + public ApiResponse> findReservationByEmployee( @RequestParam(value = "date", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @PathVariable("employeeId") Long employeeId diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java index 6e6f81c..bf3e840 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationService.java @@ -11,6 +11,6 @@ public interface ReservationService { String changeAvailability(List times, Long userId); String reservation(Long reservationId, Long userId, Long programId, LocalDateTime now); Map> findReservationForWeekByMember(LocalDate day, Long id); - Map> findReservationForWeekByEmployee(LocalDate day, Long id); + List findReservationForWeekByEmployee(LocalDate day, Long id); String cancel(Long userId, Long reservationId, LocalDateTime now); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java index dd4580a..baedc80 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/reservation/service/ReservationServiceImpl.java @@ -139,7 +139,7 @@ public Map> findReservationForWeekByMember( } @Override - public Map> findReservationForWeekByEmployee(LocalDate date, Long employeeId) { + public List findReservationForWeekByEmployee(LocalDate date, Long employeeId) { LocalDateTime startOfWeek = calStartOfWeek(date); LocalDateTime endOfWeek = calEndOfWeek(date); @@ -152,7 +152,7 @@ public Map> findReservationForWeekByEmploye return reservations.stream() .map(ReservationResponse::of) - .collect(Collectors.groupingBy(response -> response.getReservationTime().toLocalDate())); + .toList(); } //그 주의 월요일 00:00:00 @@ -165,6 +165,16 @@ private LocalDateTime calEndOfWeek(LocalDate date) { return date.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).atTime(LocalTime.MAX); } + //그 주의 월요일 00:00:00 + private LocalDateTime calStartOfDay(LocalDate date) { + return date.atStartOfDay(); + } + + //그 주의 일요일 23:59:59 + private LocalDateTime calEndOfDay(LocalDate date) { + return date.atTime(LocalTime.MAX); + } + @Override @Transactional public String cancel(Long userId, Long reservationId, LocalDateTime now) { From daa65e4d74594a2ebd31af7f04f3cfb5d0eac4d5 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Wed, 27 Mar 2024 18:50:21 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat=20:=20=ED=94=84=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EB=9E=A8=20=EC=83=81=EC=84=B8=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ProgramAdminController.java | 11 ++++++++ .../program/controller/ProgramController.java | 2 +- .../program/service/ProgramServiceImpl.java | 26 ++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java index 083ba5a..43c94a2 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramAdminController.java @@ -56,6 +56,17 @@ public ApiResponse> find( ); } + @GetMapping("/{id}") + public ApiResponse find( + @PathVariable("id") Long id) { + Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication(); + Long userId = Long.parseLong(loggedInUser.getName()); + + return ApiResponse.ok( + programService.findByProgramId(id,userId) + ); + } + @DeleteMapping("/{id}") public ApiResponse refund(@PathVariable("id") Long id) { LocalDateTime now = LocalDateTime.now(); diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java index 79cbe36..4f4cbba 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java @@ -45,7 +45,7 @@ public ApiResponse> find( } //어드민이 유저 id로 검색 - @GetMapping("/{id}") + @GetMapping("/user/{id}") public ApiResponse find( @PathVariable("id") Long id, Principal principal) { diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java index f731710..98b2f59 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java @@ -317,24 +317,32 @@ public ProgramResponse findByProgramId(long programId, long userId) { new CustomException("존재하지 않는 회원입니다.", ErrorCode.MEMBER_NOT_FOUND) ); - Program programs = programRepository.findById(programId).orElseThrow(() -> + Program program = programRepository.findById(programId).orElseThrow(() -> new CustomException(programId + "은 존재하지 않는 프로그램입니다.", ErrorCode.PROGRAM_NOT_FOUND) ); if(member.getRole().equals(MemberRole.TRAINER)) { - Employee employee = employeeRepository.findByMemberId(member.getId()).orElseThrow(() -> - new CustomException("존재하지 않는 직원입니다.", ErrorCode.EMPLOYEE_NOT_FOUND) - ); - if(Objects.equals(programs.getEmployee().getId(), employee.getId())) { - throw new CustomException("조회 권한이 없습니다.", ErrorCode.NO_AUTHORITY); - } + validTrainerAccess(member,program); + } else if(member.getRole().equals(MemberRole.MEMBER)){ + validMemberAccess(member,program); } - if(Objects.equals(programs.getMember().getId(), member.getId())) { + return ProgramResponse.of(program); + } + + private void validTrainerAccess(Member member, Program program) { + Employee employee = employeeRepository.findByMemberId(member.getId()).orElseThrow(() -> + new CustomException("존재하지 않는 직원입니다.", ErrorCode.EMPLOYEE_NOT_FOUND) + ); + if(Objects.equals(program.getEmployee().getId(), employee.getId())) { throw new CustomException("조회 권한이 없습니다.", ErrorCode.NO_AUTHORITY); } + } - return ProgramResponse.of(programs); + private void validMemberAccess(Member member, Program program) { + if(Objects.equals(program.getMember().getId(), member.getId())) { + throw new CustomException("조회 권한이 없습니다.", ErrorCode.NO_AUTHORITY); + } } private Page findProgramByEmploy(Member member, ProgramSearchStatus option,Pageable pageable) { From a209cadf068cc057034621c14c0af8327200b0d8 Mon Sep 17 00:00:00 2001 From: moonjin-kim Date: Wed, 27 Mar 2024 19:16:30 +0900 Subject: [PATCH 8/9] =?UTF-8?q?feat=20:=20valid=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EB=9E=A8=20=EC=A1=B0=ED=9A=8C=20=EC=98=B5=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../program/controller/ProgramController.java | 5 +- .../entity/enums/ProgramSearchStatus.java | 1 - .../program/entity/enums/ProgramStatus.java | 12 +- .../program/repository/ProgramRepository.java | 6 +- .../program/service/ProgramServiceImpl.java | 12 +- .../program/service/ProgramServiceTest.java | 176 +++++++++++++++--- 6 files changed, 173 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java index 4f4cbba..364c019 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/controller/ProgramController.java @@ -44,9 +44,8 @@ public ApiResponse> find( ); } - //어드민이 유저 id로 검색 - @GetMapping("/user/{id}") - public ApiResponse find( + @GetMapping("/{id}") + public ApiResponse findById( @PathVariable("id") Long id, Principal principal) { //todo : spring security 개발 후 토큰에서 userID를 전달해 줘야함. diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramSearchStatus.java b/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramSearchStatus.java index 0b7da74..55627c8 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramSearchStatus.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramSearchStatus.java @@ -4,5 +4,4 @@ public enum ProgramSearchStatus { ALL, VALID, INVALID - } diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramStatus.java b/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramStatus.java index eff03e8..40137c9 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramStatus.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/entity/enums/ProgramStatus.java @@ -1,9 +1,19 @@ package com.sideProject.PlanIT.domain.program.entity.enums; +import java.util.List; + public enum ProgramStatus { NOT_STARTED, IN_PROGRESS, SUSPEND, REFUND, - EXPIRED + EXPIRED; + + public static List forValid() { + return List.of(IN_PROGRESS); + } + + public static List forUnValid() { + return List.of(NOT_STARTED,SUSPEND,REFUND,EXPIRED); + } } diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java b/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java index e42f7df..55d8cf3 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java @@ -9,6 +9,8 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ProgramRepository extends JpaRepository { @Query("SELECT o FROM Program o WHERE o.registration.id = :registrationId") @@ -16,8 +18,8 @@ public interface ProgramRepository extends JpaRepository { //status가 IN_PROGRESS인 모든 프로그램 조회 Page findByMemberId(Long memberId, Pageable pageable); Page findByEmployeeId(Long employeeId, Pageable pageable); - Page findByMemberIdAndStatus(Long memberId, ProgramStatus status, Pageable pageable); + Page findByMemberIdAndStatusIn(Long memberId, List status, Pageable pageable); Page findByEmployeeIdAndStatus(Long employeeId,ProgramStatus status, Pageable pageable); - Page findByStatus(ProgramStatus status, Pageable pageable); + Page findByStatusIn(List status, Pageable pageable); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java index 98b2f59..fed3580 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceImpl.java @@ -361,8 +361,10 @@ private Page findProgramByUser(Member member, ProgramSearchStatus optio //ALL이면 모든 상태 조회, VALID이면 IN_PROCESS인 경우만 조회 if(option == ProgramSearchStatus.ALL) { return programRepository.findByMemberId(member.getId(),pageable); + } else if (option == ProgramSearchStatus.VALID) { + return programRepository.findByMemberIdAndStatusIn(member.getId(), ProgramStatus.forValid(),pageable); } else { - return programRepository.findByMemberIdAndStatus(member.getId(), ProgramStatus.IN_PROGRESS,pageable); + return programRepository.findByMemberIdAndStatusIn(member.getId(), ProgramStatus.forUnValid(),pageable); } } @@ -371,9 +373,9 @@ private Page findProgram(ProgramSearchStatus option,Pageable pageable) if(option == ProgramSearchStatus.ALL) { return programRepository.findAll(pageable); } else if(option == ProgramSearchStatus.VALID) { - return programRepository.findByStatus(ProgramStatus.IN_PROGRESS,pageable); + return programRepository.findByStatusIn(ProgramStatus.forValid(),pageable); } else { - return programRepository.findByStatus(ProgramStatus.IN_PROGRESS, pageable); + return programRepository.findByStatusIn(ProgramStatus.forUnValid(), pageable); } } @@ -410,6 +412,10 @@ private Page findAndConvertRegistrations(RegistrationS registrations = findRegistrationByUser(member, option, pageable); } + if (registrations == null || registrations.isEmpty()) { + throw new CustomException("조건을 만족하는 Registration이 없습니다.", ErrorCode.REGISTRATION_NOT_FOUND); + } + return registrations.map(FindRegistrationResponse::of); } diff --git a/src/test/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceTest.java b/src/test/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceTest.java index df755d5..7b8eae2 100644 --- a/src/test/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceTest.java +++ b/src/test/java/com/sideProject/PlanIT/domain/program/service/ProgramServiceTest.java @@ -40,8 +40,7 @@ import java.time.format.DateTimeFormatter; import java.util.List; -import static com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus.EXPIRED; -import static com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus.IN_PROGRESS; +import static com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus.*; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -1049,8 +1048,8 @@ void findInProgressProgramByUser(){ programRepository.save(program3); //when - Page results1 = programService.findByUser(member1.getId(), ProgramSearchStatus.INVALID, pageable); - Page results2 = programService.findByUser(member2.getId(), ProgramSearchStatus.INVALID, pageable); + Page results1 = programService.findByUser(member1.getId(), ProgramSearchStatus.VALID, pageable); + Page results2 = programService.findByUser(member2.getId(), ProgramSearchStatus.VALID, pageable); //then assertThat(results1.getContent().size()).isEqualTo(2); @@ -1255,6 +1254,147 @@ void findAllProgramByUser(){ ); } + @DisplayName("유저의 유효하지 않은 프로그램을 조회할 수 있다.") + @Test + void findInvalidProgramByUser(){ + //given + Period periodOfTenDays = Period.ofMonths(1); + Product product = initProduct("회원권 1달", periodOfTenDays,0,ProductType.MEMBERSHIP); + Employee trainer = initTrainer("employee1"); + Employee trainer2 = initTrainer("employee2"); + Member member1 = initMember("tester1",MemberRole.MEMBER); + + Pageable pageable = PageRequest.of(0, 10); + + Registration registration = Registration.builder() + .product(product) + .member(member1) + .discount(0) + .totalPrice(30000) + .status(RegistrationStatus.ACCEPTED) + .paymentAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .registrationAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .refundAt(null) + .build(); + Registration saveRegistration = registrationRepository.save(registration); + + Program program = Program.builder() + .employee(trainer) + .registration(saveRegistration) + .product(saveRegistration.getProduct()) + .member(saveRegistration.getMember()) + .status(ProgramStatus.REFUND) + .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .endAt(LocalDate.parse("2000-02-01", DateTimeFormatter.ISO_DATE)) + .build(); + programRepository.save(program); + + Registration registration2 = Registration.builder() + .product(product) + .member(member1) + .discount(0) + .totalPrice(30000) + .status(RegistrationStatus.ACCEPTED) + .paymentAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .registrationAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .refundAt(null) + .build(); + Registration saveRegistration2 = registrationRepository.save(registration2); + + Program program2 = Program.builder() + .employee(trainer) + .registration(saveRegistration2) + .product(saveRegistration2.getProduct()) + .member(saveRegistration2.getMember()) + .status(IN_PROGRESS) + .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .endAt(LocalDate.parse("2000-03-01", DateTimeFormatter.ISO_DATE)) + .build(); + programRepository.save(program2); + + Registration registration3 = Registration.builder() + .product(product) + .member(member1) + .discount(0) + .totalPrice(30000) + .status(RegistrationStatus.ACCEPTED) + .paymentAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .registrationAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .refundAt(null) + .build(); + Registration saveRegistration3 = registrationRepository.save(registration3); + + Program program3 = Program.builder() + .employee(trainer2) + .registration(saveRegistration3) + .product(saveRegistration3.getProduct()) + .member(saveRegistration3.getMember()) + .status(EXPIRED) + .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .endAt(LocalDate.parse("2000-04-01", DateTimeFormatter.ISO_DATE)) + .build(); + programRepository.save(program3); + + Registration registration4 = Registration.builder() + .product(product) + .member(member1) + .discount(0) + .totalPrice(30000) + .status(RegistrationStatus.ACCEPTED) + .paymentAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .registrationAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .refundAt(null) + .build(); + Registration saveRegistration4 = registrationRepository.save(registration4); + + Program program4 = Program.builder() + .employee(trainer2) + .registration(saveRegistration4) + .product(saveRegistration4.getProduct()) + .member(saveRegistration4.getMember()) + .status(ProgramStatus.NOT_STARTED) + .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .endAt(LocalDate.parse("2000-04-01", DateTimeFormatter.ISO_DATE)) + .build(); + programRepository.save(program4); + + Registration registration5 = Registration.builder() + .product(product) + .member(member1) + .discount(0) + .totalPrice(30000) + .status(RegistrationStatus.ACCEPTED) + .paymentAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .registrationAt(LocalDateTime.parse("2000-01-01 00:00", DATE_TIME_FORMATTER)) + .refundAt(null) + .build(); + Registration saveRegistration5 = registrationRepository.save(registration5); + + Program program5 = Program.builder() + .employee(trainer2) + .registration(saveRegistration5) + .product(saveRegistration5.getProduct()) + .member(saveRegistration5.getMember()) + .status(SUSPEND) + .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) + .endAt(LocalDate.parse("2000-04-01", DateTimeFormatter.ISO_DATE)) + .build(); + programRepository.save(program5); + + + //when + Page results1 = programService.findByUser(member1.getId(), ProgramSearchStatus.INVALID, pageable); + + //then + assertThat(results1.getContent().size()).isEqualTo(4); + assertThat(results1.getContent()).extracting("startAt","endAt","status") + .contains(tuple("2000-01-01","2000-02-01",ProgramStatus.REFUND), + tuple("2000-01-01","2000-04-01",EXPIRED), + tuple("2000-01-01","2000-04-01",NOT_STARTED), + tuple("2000-01-01","2000-04-01",SUSPEND) + ); + } + @DisplayName("트레이너의 진행중인 모든 프로그램을 조회할 수 있다.") @Test void findAllProgramByEmployee(){ @@ -1553,18 +1693,6 @@ void FindAllRegistrationByUser(){ assertThat(result2.getContent()).extracting("totalPrice","discount","status") .contains(tuple(40000,0,RegistrationStatus.PENDING) ); -// -// assertThat(result1).hasSize(4); -// assertThat(result1).extracting("member","memberId","totalPrice","discount","status") -// .contains(tuple("tester1",member1.getId(),10000,0,RegistrationStatus.DECLINED), -// tuple("tester1",member1.getId(),20000,0,RegistrationStatus.ACCEPTED), -// tuple("tester1",member1.getId(),30000,0,RegistrationStatus.PENDING), -// tuple("tester1",member1.getId(),40000,0,RegistrationStatus.REFUND) -// ); -// assertThat(result2).hasSize(1); -// assertThat(result2).extracting("member","memberId","totalPrice","discount","status") -// .contains(tuple("tester2",member2.getId(),40000,0,RegistrationStatus.PENDING) -// ); } @DisplayName("유저의 승인대기 중 인 registration을 조회 가능하다.") @Test @@ -1641,16 +1769,6 @@ void findReadyRegistrationByUser(){ Page result2 = programService.findRegistrationsByUser(member2.getId(), RegistrationSearchStatus.READY, pageable); //then -// assertThat(result1).hasSize(2); -// assertThat(result1).extracting("member","memberId","totalPrice","discount","status") -// .contains( -// tuple("tester1",member1.getId(),30000,0,RegistrationStatus.PENDING), -// tuple("tester1",member1.getId(),40000,0,RegistrationStatus.PENDING) -// ); -// assertThat(result2).hasSize(1); -// assertThat(result2).extracting("member","memberId","totalPrice","discount","status") -// .contains(tuple("tester2",member2.getId(),40000,0,RegistrationStatus.PENDING) -// ); assertThat(result1.getContent()).hasSize(2); assertThat(result1.getContent()).extracting("totalPrice","discount","status") .contains( @@ -1663,7 +1781,7 @@ void findReadyRegistrationByUser(){ ); } - @DisplayName("실패 : registration이 없을때 조회를 하면 예외가 발생한다.") + @DisplayName("실패 : registration이 없으면 빈 객체가 온다.") @Test void findRegistrationNoExist(){ //given @@ -2000,7 +2118,7 @@ void suspendProgram(){ //then assertThat(result).isEqualTo(program.getId()); - assertThat(program1.getStatus()).isEqualTo(ProgramStatus.SUSPEND); + assertThat(program1.getStatus()).isEqualTo(SUSPEND); assertThat(program1.getStartAt()).isEqualTo(program.getStartAt()); assertThat(program1.getEndAt()).isEqualTo(program.getEndAt()); assertThat(program1.getSuspendAt()).isEqualTo(now); @@ -2112,7 +2230,7 @@ void resumeProgram(){ .registration(saveRegistration) .product(saveRegistration.getProduct()) .member(saveRegistration.getMember()) - .status(ProgramStatus.SUSPEND) + .status(SUSPEND) .suspendAt(stopDay) .startAt(LocalDate.parse("2000-01-01", DateTimeFormatter.ISO_DATE)) .endAt(LocalDate.parse("2000-02-01", DateTimeFormatter.ISO_DATE)) From 07e01bcf5e802788549529a1f32fe026924c5497 Mon Sep 17 00:00:00 2001 From: JuhyunPark Date: Wed, 27 Mar 2024 19:20:14 +0900 Subject: [PATCH 9/9] =?UTF-8?q?Feat:=20=ED=9A=8C=EC=9B=90=EA=B6=8C=20?= =?UTF-8?q?=EB=A7=8C=EB=A3=8C=20=EC=95=8C=EB=A6=BC=20=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sideProject/PlanIT/PlanItApplication.java | 2 + .../common/scheduler/MemberShipScheduler.java | 52 +++++++++++++++++++ .../program/repository/ProgramRepository.java | 8 ++- .../domain/user/service/EmailService.java | 14 ++++- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/sideProject/PlanIT/common/scheduler/MemberShipScheduler.java diff --git a/src/main/java/com/sideProject/PlanIT/PlanItApplication.java b/src/main/java/com/sideProject/PlanIT/PlanItApplication.java index 4243417..06fe7e5 100644 --- a/src/main/java/com/sideProject/PlanIT/PlanItApplication.java +++ b/src/main/java/com/sideProject/PlanIT/PlanItApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; +@EnableScheduling @SpringBootApplication public class PlanItApplication { diff --git a/src/main/java/com/sideProject/PlanIT/common/scheduler/MemberShipScheduler.java b/src/main/java/com/sideProject/PlanIT/common/scheduler/MemberShipScheduler.java new file mode 100644 index 0000000..fac2eba --- /dev/null +++ b/src/main/java/com/sideProject/PlanIT/common/scheduler/MemberShipScheduler.java @@ -0,0 +1,52 @@ +package com.sideProject.PlanIT.common.scheduler; + +import com.sideProject.PlanIT.domain.product.entity.enums.ProductType; +import com.sideProject.PlanIT.domain.program.entity.Program; +import com.sideProject.PlanIT.domain.program.repository.ProgramRepository; +import com.sideProject.PlanIT.domain.user.service.EmailService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; + +@Component +@RequiredArgsConstructor +@Slf4j +public class MemberShipScheduler { + private final ProgramRepository programRepository; + private final EmailService emailService; + + @Scheduled(cron = "0 0 0 * * ?") + public void memberShipEndTimeEvent() { + log.info("이메일 전송"); + LocalDate nowDate = LocalDate.now(); + + LocalDate afterOneWeek = nowDate.plusWeeks(1); + LocalDate afterOneMonth = nowDate.plusMonths(1); + + sendMailToOneWeekLeft(afterOneWeek); + sendMailToOneMonthLeft(afterOneMonth); + } + + private void sendMailToOneWeekLeft(LocalDate afterOneWeek) { + List oneWeekLefts = programRepository.findMembershipProgramsByEndAtAndProductType(afterOneWeek, ProductType.MEMBERSHIP); + + oneWeekLefts.forEach(program -> { + emailService.memberShipEmail(program.getMember().getEmail(), "일주일"); + }); + } + + private void sendMailToOneMonthLeft(LocalDate afterOneMonth) { + List oneWeekLefts = programRepository.findMembershipProgramsByEndAtAndProductType(afterOneMonth, ProductType.MEMBERSHIP); + + oneWeekLefts.forEach(program -> { + emailService.memberShipEmail(program.getMember().getEmail(), "한 달"); + }); + } + + + +} diff --git a/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java b/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java index e42f7df..045f03d 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java +++ b/src/main/java/com/sideProject/PlanIT/domain/program/repository/ProgramRepository.java @@ -1,7 +1,8 @@ package com.sideProject.PlanIT.domain.program.repository; -import com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus; +import com.sideProject.PlanIT.domain.product.entity.enums.ProductType; import com.sideProject.PlanIT.domain.program.entity.Program; +import com.sideProject.PlanIT.domain.program.entity.enums.ProgramStatus; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,6 +10,9 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.time.LocalDate; +import java.util.List; + @Repository public interface ProgramRepository extends JpaRepository { @Query("SELECT o FROM Program o WHERE o.registration.id = :registrationId") @@ -20,4 +24,6 @@ public interface ProgramRepository extends JpaRepository { Page findByEmployeeIdAndStatus(Long employeeId,ProgramStatus status, Pageable pageable); Page findByStatus(ProgramStatus status, Pageable pageable); + @Query("SELECT p FROM Program p JOIN p.product pr WHERE p.endAt = ?1 AND pr.type = ?2") + List findMembershipProgramsByEndAtAndProductType(LocalDate endAt, ProductType productType); } diff --git a/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java index 0e72903..5cb5a4d 100644 --- a/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java +++ b/src/main/java/com/sideProject/PlanIT/domain/user/service/EmailService.java @@ -40,12 +40,24 @@ public String joinEmail(String email) { "

" + "인증 번호는 [" + authNumber + "]입니다." + "
" + - "인증번호를 입력해주세요"; //이메일 내용 삽입 + "인증번호를 입력해주세요"; mailSend(setFrom, toMail, title, content); redisUtil.setMailValidation(email, String.valueOf(authNumber)); return "이메일 전송 완료"; } + public String memberShipEmail(String email, String expireTime) { + String setFrom = "planitvalidation@gmail.com"; + String toMail = email; + String title = "[PlanIT] 회원권 만료 예정 알림입니다!."; + String content = + "PlanIT를 이용해주시는 감사한 고객님께 안내 말씀 드립니다." + + "

" + + "고객님께서 이용 중이신 회원권의 만료 기간이 " + expireTime + "남았습니다."; + mailSend(setFrom, toMail, title, content); + return "이메일 전송 완료"; + } + private void mailSend(String setFrom, String toMail, String title, String content) { MimeMessage message = mailSender.createMimeMessage(); try {