From 228a1a2a8cabfe56b1e493db6491e7f6568c6013 Mon Sep 17 00:00:00 2001 From: LeeKiWoo Date: Wed, 13 Sep 2023 02:26:30 +0900 Subject: [PATCH] fix(auth): fix an error related authenticate and getting team detail (#133) * refactor(meeting): add filtering logic when check meeting request duplicated * refactor(meeting): modify the logic of inquiring about likes and meeting request data * fix(meeting): fix an error when querying a list of successful meetings & refresh api (#129) * fix(meeting): add result that meeting list from my request to find accepted meeting list query * refactor(auth): change RefreshToken key name * test(auth): fix refresh test and add API specification * test(auth): fix refresh test and add API specification * test(auth): fix refresh test and add API specification * fix(meeting): fix test fail in workflow CI --------- Co-authored-by: KAispread * refactor(auth): modify refresh api --- .../controller/GlobalExceptionController.java | 3 +- .../controller/meeting/MeetingController.java | 6 +- .../controller/team/TeamController.java | 4 +- .../meeting/MeetingRequestRepository.java | 7 +- .../domain/member/MemberRepository.java | 3 +- .../domain/team/TeamCustomRepository.java | 3 +- .../domain/team/TeamCustomRepositoryImpl.java | 35 ++++--- .../wemeet/dto/dsl/TeamInformationDto.java | 8 +- .../com/e2i/wemeet/exception/ErrorCode.java | 1 + .../token/RefreshTokenNotExistException.java | 15 +++ .../security/config/SecurityBeanConfig.java | 5 +- .../filter/RefreshTokenProcessingFilter.java | 27 ++++-- .../admin/TokenAuthorizationService.java | 26 ------ .../service/heart/HeartServiceImpl.java | 3 +- .../service/meeting/MeetingHandleService.java | 4 +- .../meeting/MeetingHandleServiceImpl.java | 20 ++-- .../e2i/wemeet/service/team/TeamService.java | 3 +- .../wemeet/service/team/TeamServiceImpl.java | 7 +- .../util/aspect/TokenValidationAspect.java | 8 +- src/main/resources/messages.properties | 1 + .../RefreshTokenProcessingFilterTest.java | 5 +- .../meeting/MeetingControllerTest.java | 15 +-- .../controller/team/TeamControllerTest.java | 8 +- .../meeting/MeetingRequestRepositoryTest.java | 7 +- .../team/TeamCustomRepositoryImplTest.java | 91 ++++++++++++++++--- .../e2i/wemeet/redis/RedisConnectionTest.java | 26 +++++- .../meeting/MeetingHandleServiceImplTest.java | 66 +++++++++++--- .../service/team/TeamServiceImplTest.java | 4 +- 28 files changed, 280 insertions(+), 131 deletions(-) create mode 100644 src/main/java/com/e2i/wemeet/exception/token/RefreshTokenNotExistException.java delete mode 100644 src/main/java/com/e2i/wemeet/service/admin/TokenAuthorizationService.java diff --git a/src/main/java/com/e2i/wemeet/controller/GlobalExceptionController.java b/src/main/java/com/e2i/wemeet/controller/GlobalExceptionController.java index 8dcc8f93..f79a1588 100644 --- a/src/main/java/com/e2i/wemeet/controller/GlobalExceptionController.java +++ b/src/main/java/com/e2i/wemeet/controller/GlobalExceptionController.java @@ -19,6 +19,7 @@ import com.e2i.wemeet.exception.token.NotEqualRoleToTokenException; import com.e2i.wemeet.exception.unauthorized.UnAuthorizedException; import jakarta.validation.ValidationException; +import java.lang.reflect.UndeclaredThrowableException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.JDBCException; @@ -148,7 +149,7 @@ public ResponseEntity handleNotEqualRoleException( } // SQL 관련 예외 핸들링 + sql & sql 예외 원인 Logging - @ExceptionHandler(DataAccessException.class) + @ExceptionHandler({DataAccessException.class, UndeclaredThrowableException.class}) public ResponseEntity handleDatabaseAccessException( final DataAccessException e) { final int code = DATA_ACCESS.getCode(); diff --git a/src/main/java/com/e2i/wemeet/controller/meeting/MeetingController.java b/src/main/java/com/e2i/wemeet/controller/meeting/MeetingController.java index bc4d4629..70d368c8 100644 --- a/src/main/java/com/e2i/wemeet/controller/meeting/MeetingController.java +++ b/src/main/java/com/e2i/wemeet/controller/meeting/MeetingController.java @@ -31,7 +31,8 @@ public class MeetingController { @PostMapping public ResponseDto sendMeetingRequest(@MemberId Long memberId, @RequestBody @Valid SendMeetingRequestDto requestDto) { - meetingHandleService.sendRequest(requestDto, memberId); + LocalDateTime meetingRequestTime = LocalDateTime.now(); + meetingHandleService.sendRequest(requestDto, memberId, meetingRequestTime); return ResponseDto.success("Send meeting request success"); } @@ -39,7 +40,8 @@ public ResponseDto sendMeetingRequest(@MemberId Long memberId, @RequestBod @PostMapping("/message") public ResponseDto sendMeetingRequestWithMessage(@MemberId Long memberId, @RequestBody @Valid SendMeetingWithMessageRequestDto requestDto) { - meetingHandleService.sendRequestWithMessage(requestDto, memberId); + LocalDateTime meetingRequestTime = LocalDateTime.now(); + meetingHandleService.sendRequestWithMessage(requestDto, memberId, meetingRequestTime); return ResponseDto.success("Send meeting request with message success"); } diff --git a/src/main/java/com/e2i/wemeet/controller/team/TeamController.java b/src/main/java/com/e2i/wemeet/controller/team/TeamController.java index 944a7bfa..15557145 100644 --- a/src/main/java/com/e2i/wemeet/controller/team/TeamController.java +++ b/src/main/java/com/e2i/wemeet/controller/team/TeamController.java @@ -10,6 +10,7 @@ import com.e2i.wemeet.security.manager.IsManager; import com.e2i.wemeet.service.team.TeamService; import jakarta.validation.Valid; +import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; @@ -58,7 +59,8 @@ public ResponseDto readTeam(@MemberId Long memberId) { @GetMapping("/{teamId}") public ResponseDto readTeamById(@MemberId Long memberId, @PathVariable Long teamId) { - TeamDetailResponseDto result = teamService.readByTeamId(memberId, teamId); + final LocalDateTime readTime = LocalDateTime.now(); + TeamDetailResponseDto result = teamService.readByTeamId(memberId, teamId, readTime); return ResponseDto.success("Get Team Detail Success", result); } diff --git a/src/main/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepository.java b/src/main/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepository.java index 1dbf4275..2f5e5459 100644 --- a/src/main/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepository.java +++ b/src/main/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepository.java @@ -2,6 +2,7 @@ import com.e2i.wemeet.domain.meeting.data.AcceptStatus; import com.e2i.wemeet.domain.team.Team; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -24,11 +25,11 @@ public interface MeetingRequestRepository extends JpaRepository findIdByTeamIdAndPartnerTeamId(@Param("teamId") Long teamId, @Param("partnerTeamId") Long partnerTeamId); + Optional findIdByTeamIdAndPartnerTeamId(@Param("teamId") Long teamId, @Param("partnerTeamId") Long partnerTeamId); // 팀의 이전 미팅 신청 이력 조회 (신청 상태 조건) @Query(""" diff --git a/src/main/java/com/e2i/wemeet/domain/member/MemberRepository.java b/src/main/java/com/e2i/wemeet/domain/member/MemberRepository.java index 8c6147b4..c3529ddf 100644 --- a/src/main/java/com/e2i/wemeet/domain/member/MemberRepository.java +++ b/src/main/java/com/e2i/wemeet/domain/member/MemberRepository.java @@ -19,5 +19,6 @@ public interface MemberRepository extends JpaRepository { Optional findCreditByMemberId(@Param("memberId") Long memberId); @Query("select m.role from Member m where m.memberId = :memberId") - Role findRoleByMemberId(Long memberId); + Optional findRoleByMemberId(@Param("memberId") Long memberId); + } \ No newline at end of file diff --git a/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepository.java b/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepository.java index 0ebe9813..6b67d109 100644 --- a/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepository.java +++ b/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepository.java @@ -3,6 +3,7 @@ import com.e2i.wemeet.domain.team.data.TeamImageData; import com.e2i.wemeet.dto.dsl.TeamInformationDto; import com.e2i.wemeet.dto.response.LeaderResponseDto; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -21,6 +22,6 @@ public interface TeamCustomRepository { /* * 팀 정보 조회 * */ - Optional findTeamInformationByTeamId(Long memberLeaderId, Long teamId); + Optional findTeamInformationByTeamId(Long memberLeaderId, Long teamId, LocalDateTime readTime); } diff --git a/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImpl.java b/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImpl.java index 43ad5b00..e0478324 100644 --- a/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImpl.java +++ b/src/main/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImpl.java @@ -7,6 +7,8 @@ import static com.e2i.wemeet.domain.team.QTeam.team; import static com.e2i.wemeet.domain.team_image.QTeamImage.teamImage; import static com.e2i.wemeet.domain.team_member.QTeamMember.teamMember; +import static com.e2i.wemeet.service.heart.HeartServiceImpl.HEART_EXPIRE_DAY; +import static com.e2i.wemeet.service.meeting.MeetingHandleServiceImpl.MEETING_REQUEST_EXPIRE_DAY; import com.e2i.wemeet.domain.team.data.TeamImageData; import com.e2i.wemeet.dto.dsl.TeamInformationDto; @@ -14,7 +16,9 @@ import com.e2i.wemeet.dto.response.LeaderResponseDto; import com.e2i.wemeet.exception.notfound.TeamNotFoundException; import com.querydsl.core.types.Projections; +import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; import java.util.Optional; @@ -60,7 +64,7 @@ public Optional findLeaderByTeamId(final Long teamId) { } @Override - public Optional findTeamInformationByTeamId(final Long memberLeaderId, final Long teamId) { + public Optional findTeamInformationByTeamId(final Long memberLeaderId, final Long teamId, final LocalDateTime readTime) { com.e2i.wemeet.domain.team.QTeam myTeam = new com.e2i.wemeet.domain.team.QTeam("myTeam"); TeamInformationDto teamInformationDto = Optional.ofNullable(queryFactory .select(Projections.constructor(TeamInformationDto.class, @@ -73,20 +77,29 @@ public Optional findTeamInformationByTeamId(final Long membe team.additionalActivity, team.introduction, team.deletedAt, - meetingRequest.acceptStatus, - heart.heartId, + // 미팅 요청 조회 + JPAExpressions + .select(meetingRequest.acceptStatus) + .from(meetingRequest) + .where(meetingRequest.team.eq(myTeam), + meetingRequest.partnerTeam.eq(team), + meetingRequest.createdAt.goe(readTime.minusDays(MEETING_REQUEST_EXPIRE_DAY)) + ) + .orderBy(meetingRequest.createdAt.desc()) + .limit(1), + // 좋아요 표시 여부 조회 + JPAExpressions + .select(heart.heartId) + .from(heart) + .where(heart.team.eq(myTeam), + heart.partnerTeam.eq(team), + heart.createdAt.goe(readTime.minusDays(HEART_EXPIRE_DAY)) + ) + .limit(1), myTeam.teamId )) .from(team) .leftJoin(myTeam).on(myTeam.teamLeader.memberId.eq(memberLeaderId)) - .leftJoin(heart).on( - heart.team.eq(myTeam), - heart.partnerTeam.teamId.eq(teamId) - ) - .leftJoin(meetingRequest).on( - meetingRequest.team.eq(myTeam), - meetingRequest.partnerTeam.teamId.eq(teamId) - ) .where(team.teamId.eq(teamId)) .fetchOne()) .orElseThrow(TeamNotFoundException::new); diff --git a/src/main/java/com/e2i/wemeet/dto/dsl/TeamInformationDto.java b/src/main/java/com/e2i/wemeet/dto/dsl/TeamInformationDto.java index f4b885f6..3414c449 100644 --- a/src/main/java/com/e2i/wemeet/dto/dsl/TeamInformationDto.java +++ b/src/main/java/com/e2i/wemeet/dto/dsl/TeamInformationDto.java @@ -48,11 +48,11 @@ public TeamInformationDto(Long teamId, String chatLink, Integer memberNum, Regio this.memberHasTeam = requestMemberTeamId != null; } - public static TeamInformationDto of(Team team) { + public static TeamInformationDto of(Team team, Long heartId, Long requestMemberTeamId, AcceptStatus status) { TeamInformationDto dto = TeamInformationDto.builder() .teamId(team.getTeamId()) .chatLink(team.getChatLink()) - .heartId(1L) + .heartId(heartId) .memberNum(team.getMemberNum()) .region(team.getRegion()) .drinkRate(team.getDrinkRate()) @@ -60,8 +60,8 @@ public static TeamInformationDto of(Team team) { .additionalActivity(team.getAdditionalActivity()) .introduction(team.getIntroduction()) .deletedAt(team.getDeletedAt()) - .meetingRequestStatus(AcceptStatus.PENDING) - .requestMemberTeamId(1L) + .meetingRequestStatus(status) + .requestMemberTeamId(requestMemberTeamId) .build(); dto.setTeamMember(team.getTeamMembers()); diff --git a/src/main/java/com/e2i/wemeet/exception/ErrorCode.java b/src/main/java/com/e2i/wemeet/exception/ErrorCode.java index 817e0a49..fd46999e 100644 --- a/src/main/java/com/e2i/wemeet/exception/ErrorCode.java +++ b/src/main/java/com/e2i/wemeet/exception/ErrorCode.java @@ -70,6 +70,7 @@ public enum ErrorCode { ACCESS_TOKEN_NOT_FOUND(40207, "access.token.not.found"), MEETING_REQUEST_NOT_FOUND(40208, "meeting.request.not.found"), MEETING_NOT_FOUND(40209, "meeting.not.found"), + REFRESH_TOKEN_NOT_EXIST(40210, "refresh.token.not.exist"), UNAUTHORIZED(40300, "unauthorized"), UNAUTHORIZED_ROLE(40301, "unauthorized.role"), diff --git a/src/main/java/com/e2i/wemeet/exception/token/RefreshTokenNotExistException.java b/src/main/java/com/e2i/wemeet/exception/token/RefreshTokenNotExistException.java new file mode 100644 index 00000000..711a1009 --- /dev/null +++ b/src/main/java/com/e2i/wemeet/exception/token/RefreshTokenNotExistException.java @@ -0,0 +1,15 @@ +package com.e2i.wemeet.exception.token; + +import com.e2i.wemeet.exception.ErrorCode; + +public class RefreshTokenNotExistException extends TokenException { + + public RefreshTokenNotExistException() { + super(ErrorCode.REFRESH_TOKEN_NOT_EXIST); + } + + public RefreshTokenNotExistException(ErrorCode errorCode) { + super(errorCode); + } + +} diff --git a/src/main/java/com/e2i/wemeet/security/config/SecurityBeanConfig.java b/src/main/java/com/e2i/wemeet/security/config/SecurityBeanConfig.java index 67015dbd..9f93f052 100644 --- a/src/main/java/com/e2i/wemeet/security/config/SecurityBeanConfig.java +++ b/src/main/java/com/e2i/wemeet/security/config/SecurityBeanConfig.java @@ -16,7 +16,6 @@ import com.e2i.wemeet.security.token.TokenInjector; import com.e2i.wemeet.security.token.handler.AccessTokenHandler; import com.e2i.wemeet.security.token.handler.RefreshTokenHandler; -import com.e2i.wemeet.service.admin.TokenAuthorizationService; import com.e2i.wemeet.service.credential.sms.SmsCredentialService; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; @@ -71,9 +70,9 @@ public RefreshTokenProcessingFilter refreshTokenProcessingFilter( RedisTemplate redisTemplate, RefreshTokenHandler refreshTokenHandler, TokenInjector tokenInjector, ObjectMapper objectMapper, AccessTokenHandler accessTokenHandler, - TokenAuthorizationService tokenAuthorizationService) { + MemberRepository memberRepository) { return new RefreshTokenProcessingFilter(redisTemplate, refreshTokenHandler, tokenInjector, - objectMapper, accessTokenHandler, tokenAuthorizationService); + objectMapper, accessTokenHandler, memberRepository); } @Bean diff --git a/src/main/java/com/e2i/wemeet/security/filter/RefreshTokenProcessingFilter.java b/src/main/java/com/e2i/wemeet/security/filter/RefreshTokenProcessingFilter.java index 1d6a8fdc..ddacb3b8 100644 --- a/src/main/java/com/e2i/wemeet/security/filter/RefreshTokenProcessingFilter.java +++ b/src/main/java/com/e2i/wemeet/security/filter/RefreshTokenProcessingFilter.java @@ -2,15 +2,17 @@ import static org.springframework.http.HttpMethod.POST; +import com.e2i.wemeet.domain.member.MemberRepository; import com.e2i.wemeet.domain.member.data.Role; import com.e2i.wemeet.dto.response.ResponseDto; +import com.e2i.wemeet.exception.notfound.MemberNotFoundException; import com.e2i.wemeet.exception.token.RefreshTokenMismatchException; +import com.e2i.wemeet.exception.token.RefreshTokenNotExistException; import com.e2i.wemeet.security.token.JwtEnv; import com.e2i.wemeet.security.token.Payload; import com.e2i.wemeet.security.token.TokenInjector; import com.e2i.wemeet.security.token.handler.AccessTokenHandler; import com.e2i.wemeet.security.token.handler.RefreshTokenHandler; -import com.e2i.wemeet.service.admin.TokenAuthorizationService; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -22,6 +24,7 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; /* @@ -40,21 +43,20 @@ public class RefreshTokenProcessingFilter extends OncePerRequestFilter { private final TokenInjector tokenInjector; private final ObjectMapper objectMapper; private final AccessTokenHandler accessTokenHandler; - - private final TokenAuthorizationService tokenAuthorizationService; + private final MemberRepository memberRepository; public RefreshTokenProcessingFilter(RedisTemplate redisTemplate, RefreshTokenHandler refreshTokenHandler, TokenInjector tokenInjector, ObjectMapper objectMapper, AccessTokenHandler accessTokenHandler, - TokenAuthorizationService tokenAuthorizationService) { + MemberRepository memberRepository) { this.filterRequestMatcher = new AntPathRequestMatcher(REFRESH_REQUEST_URL, POST.name()); this.redisTemplate = redisTemplate; this.refreshTokenHandler = refreshTokenHandler; this.tokenInjector = tokenInjector; this.objectMapper = objectMapper; this.accessTokenHandler = accessTokenHandler; - this.tokenAuthorizationService = tokenAuthorizationService; + this.memberRepository = memberRepository; } @Override @@ -75,13 +77,14 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse private void reIssueToken(HttpServletRequest request, HttpServletResponse response) throws IOException { Payload payload = getPayload(request); - validateRefreshToken(request, payload); + Role role = memberRepository.findRoleByMemberId(payload.getMemberId()) + .orElseThrow(MemberNotFoundException::new); - Role role = tokenAuthorizationService.getMemberRoleByMemberId(payload.getMemberId()); - payload = new Payload(payload.getMemberId(), role.name()); + validateRefreshToken(request, payload); + Payload newPayloadForToken = new Payload(payload.getMemberId(), role.name()); - tokenInjector.injectToken(response, payload); - writeResponse(response, payload); + tokenInjector.injectToken(response, newPayloadForToken); + writeResponse(response, newPayloadForToken); } private Payload getPayload(HttpServletRequest request) { @@ -109,6 +112,10 @@ private boolean matchesRefreshTokenInRedis(Payload payload, String refreshToken) String redisKey = JwtEnv.getRedisKeyForRefresh(payload); String savedRefresh = operations.get(redisKey); + if (!StringUtils.hasText(savedRefresh)) { + throw new RefreshTokenNotExistException(); + } + boolean tokenEquals = refreshToken.equals(savedRefresh); if (tokenEquals) { // Redis 에서 RefreshToken 삭제 diff --git a/src/main/java/com/e2i/wemeet/service/admin/TokenAuthorizationService.java b/src/main/java/com/e2i/wemeet/service/admin/TokenAuthorizationService.java deleted file mode 100644 index 8b7f7736..00000000 --- a/src/main/java/com/e2i/wemeet/service/admin/TokenAuthorizationService.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.e2i.wemeet.service.admin; - -import com.e2i.wemeet.domain.member.MemberRepository; -import com.e2i.wemeet.domain.member.data.Role; -import com.e2i.wemeet.exception.notfound.MemberNotFoundException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -@Slf4j -@RequiredArgsConstructor -@Service -public class TokenAuthorizationService { - - private final MemberRepository memberRepository; - - public Role getMemberRoleByMemberId(Long memberId) { - Role memberRole = memberRepository.findRoleByMemberId(memberId); - - if (memberRole == null) { - throw new MemberNotFoundException(); - } - - return memberRole; - } -} diff --git a/src/main/java/com/e2i/wemeet/service/heart/HeartServiceImpl.java b/src/main/java/com/e2i/wemeet/service/heart/HeartServiceImpl.java index a4d5f297..d0d44096 100644 --- a/src/main/java/com/e2i/wemeet/service/heart/HeartServiceImpl.java +++ b/src/main/java/com/e2i/wemeet/service/heart/HeartServiceImpl.java @@ -24,6 +24,7 @@ @Service public class HeartServiceImpl implements HeartService { + public static final int HEART_EXPIRE_DAY = 1; private static final LocalTime boundaryTime = LocalTime.of(23, 11); private final HeartRepository heartRepository; private final MemberRepository memberRepository; @@ -87,7 +88,7 @@ public List getReceivedHeart(Long memberId, private void checkTodayHeart(Long teamId, LocalDateTime requestTime) { LocalDateTime boundaryDateTime = requestTime.with(boundaryTime); if (requestTime.isBefore(boundaryDateTime)) { - boundaryDateTime = boundaryDateTime.minusDays(1); + boundaryDateTime = boundaryDateTime.minusDays(HEART_EXPIRE_DAY); } heartRepository.findTodayHeart(teamId, boundaryDateTime, requestTime) diff --git a/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleService.java b/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleService.java index 41349ad6..f0b9c866 100644 --- a/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleService.java +++ b/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleService.java @@ -10,12 +10,12 @@ public interface MeetingHandleService { /* * 미팅 신청 * */ - void sendRequest(SendMeetingRequestDto requestDto, Long memberId); + Long sendRequest(SendMeetingRequestDto requestDto, Long memberId, LocalDateTime meetingRequestTime); /* * 쪽지와 함께 미팅 신청 * */ - void sendRequestWithMessage(SendMeetingWithMessageRequestDto requestDto, Long memberId); + Long sendRequestWithMessage(SendMeetingWithMessageRequestDto requestDto, Long memberId, LocalDateTime meetingRequestTime); /* * 미팅 신청 수락 diff --git a/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImpl.java b/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImpl.java index 1cd56587..1641d627 100644 --- a/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImpl.java +++ b/src/main/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImpl.java @@ -52,40 +52,41 @@ public class MeetingHandleServiceImpl implements MeetingHandleService { @Transactional @CostAuthorize(type = MEETING_REQUEST, role = Role.MANAGER) @Override - public void sendRequest(final SendMeetingRequestDto requestDto, final Long memberLeaderId) { + public Long sendRequest(final SendMeetingRequestDto requestDto, final Long memberLeaderId, final LocalDateTime meetingRequestTime) { Team team = meetingRepository.findTeamReferenceByLeaderId(memberLeaderId); Team partnerTeam = meetingRepository.findTeamReferenceById(requestDto.partnerTeamId()); - checkDuplicateMeetingRequest(team, partnerTeam); + checkDuplicateMeetingRequest(team, partnerTeam, meetingRequestTime); MeetingRequest meetingRequest = MeetingRequest.builder() .team(team) .partnerTeam(partnerTeam) .build(); - - meetingRequestRepository.save(meetingRequest); + MeetingRequest request = meetingRequestRepository.save(meetingRequest); // 이벤트 발행 publishMeetingEvent(getMeetingRequestMessage(), memberLeaderId, partnerTeam); + return request.getMeetingRequestId(); } @Transactional @CostAuthorize(type = MEETING_REQUEST_WITH_MESSAGE, role = Role.MANAGER) @Override - public void sendRequestWithMessage(final SendMeetingWithMessageRequestDto requestDto, final Long memberLeaderId) { + public Long sendRequestWithMessage(final SendMeetingWithMessageRequestDto requestDto, final Long memberLeaderId, + final LocalDateTime meetingRequestTime) { Team team = meetingRepository.findTeamReferenceByLeaderId(memberLeaderId); Team partnerTeam = meetingRepository.findTeamReferenceById(requestDto.partnerTeamId()); - checkDuplicateMeetingRequest(team, partnerTeam); + checkDuplicateMeetingRequest(team, partnerTeam, meetingRequestTime); MeetingRequest meetingRequest = MeetingRequest.builder() .team(team) .partnerTeam(partnerTeam) .message(requestDto.message()) .build(); - - meetingRequestRepository.save(meetingRequest); + MeetingRequest request = meetingRequestRepository.save(meetingRequest); // 이벤트 발행 publishMeetingEvent(getMeetingRequestMessage(), memberLeaderId, partnerTeam); + return request.getMeetingRequestId(); } @Transactional @@ -173,8 +174,9 @@ private void publishMeetingEvent(final String message, final Long memberLeaderId } // 중복된 미팅 요청인지 검증 - private void checkDuplicateMeetingRequest(Team team, Team partnerTeam) { + private void checkDuplicateMeetingRequest(Team team, Team partnerTeam, LocalDateTime meetingRequestTime) { meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(team.getTeamId(), partnerTeam.getTeamId()) + .filter(meetingRequestCreatedAt -> !isExpiredOfDays(meetingRequestCreatedAt, meetingRequestTime, MEETING_REQUEST_EXPIRE_DAY)) .ifPresent(meetingRequestId -> { throw new DuplicateMeetingRequestException(); }); diff --git a/src/main/java/com/e2i/wemeet/service/team/TeamService.java b/src/main/java/com/e2i/wemeet/service/team/TeamService.java index 740f6ce0..10f94be0 100644 --- a/src/main/java/com/e2i/wemeet/service/team/TeamService.java +++ b/src/main/java/com/e2i/wemeet/service/team/TeamService.java @@ -4,6 +4,7 @@ import com.e2i.wemeet.dto.request.team.UpdateTeamRequestDto; import com.e2i.wemeet.dto.response.team.MyTeamResponseDto; import com.e2i.wemeet.dto.response.team.TeamDetailResponseDto; +import java.time.LocalDateTime; import java.util.List; import org.springframework.web.multipart.MultipartFile; @@ -30,7 +31,7 @@ void updateTeam(Long memberId, UpdateTeamRequestDto updateTeamRequestDto, /* * 팀 상세 조회 */ - TeamDetailResponseDto readByTeamId(Long memberId, Long teamId); + TeamDetailResponseDto readByTeamId(Long memberId, Long teamId, LocalDateTime readTime); /* * 팀 삭제 diff --git a/src/main/java/com/e2i/wemeet/service/team/TeamServiceImpl.java b/src/main/java/com/e2i/wemeet/service/team/TeamServiceImpl.java index e304319a..46dcedf8 100644 --- a/src/main/java/com/e2i/wemeet/service/team/TeamServiceImpl.java +++ b/src/main/java/com/e2i/wemeet/service/team/TeamServiceImpl.java @@ -41,7 +41,7 @@ public class TeamServiceImpl implements TeamService { private final CodeRepository codeRepository; private final S3Service s3Service; - + @Value("${aws.s3.teamImageBucket}") private String teamImageBucket; @@ -109,9 +109,8 @@ public MyTeamResponseDto readTeam(Long memberId) { @Transactional @Override - public TeamDetailResponseDto readByTeamId(final Long memberId, final Long teamId) { - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(memberId, - teamId) + public TeamDetailResponseDto readByTeamId(final Long memberId, final Long teamId, final LocalDateTime readTime) { + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(memberId, teamId, readTime) .orElseThrow(TeamNotFoundException::new); LeaderResponseDto leader = teamRepository.findLeaderByTeamId(teamId) .orElseThrow(TeamNotFoundException::new); diff --git a/src/main/java/com/e2i/wemeet/util/aspect/TokenValidationAspect.java b/src/main/java/com/e2i/wemeet/util/aspect/TokenValidationAspect.java index cfba4160..d005027f 100644 --- a/src/main/java/com/e2i/wemeet/util/aspect/TokenValidationAspect.java +++ b/src/main/java/com/e2i/wemeet/util/aspect/TokenValidationAspect.java @@ -1,10 +1,11 @@ package com.e2i.wemeet.util.aspect; +import com.e2i.wemeet.domain.member.MemberRepository; import com.e2i.wemeet.domain.member.data.Role; import com.e2i.wemeet.exception.badrequest.TeamNotExistsException; +import com.e2i.wemeet.exception.notfound.MemberNotFoundException; import com.e2i.wemeet.exception.token.NotEqualRoleToTokenException; import com.e2i.wemeet.security.model.MemberPrincipal; -import com.e2i.wemeet.service.admin.TokenAuthorizationService; import lombok.RequiredArgsConstructor; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @@ -16,7 +17,7 @@ @Aspect public class TokenValidationAspect { - private final TokenAuthorizationService tokenAuthorizationService; + private final MemberRepository memberRepository; @Before("@annotation(com.e2i.wemeet.security.manager.IsManager)") public void checkCustomAuthorization() { @@ -27,7 +28,8 @@ public void checkCustomAuthorization() { if (!principal.hasManagerRole()) { Long memberId = principal.getMemberId(); - Role memberRole = tokenAuthorizationService.getMemberRoleByMemberId(memberId); + Role memberRole = memberRepository.findRoleByMemberId(memberId) + .orElseThrow(MemberNotFoundException::new); if (memberRole.name().equals(Role.MANAGER.name())) { throw new NotEqualRoleToTokenException(); } else { diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 48a95848..4843fec5 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -84,6 +84,7 @@ team.not.found=팀을 찾을 수 없습니다. meeting.request.not.found=미팅 요청을 찾을 수 없습니다. meeting.not.found=미팅을 찾을 수 없습니다. cost.not.found=Cost 정보를 찾을 수 없습니다. +refresh.token.not.exist=저장소에 해당 유저의 RefreshToken이 존재하지 않습니다. # Expired expired=요청 대상이 만료되어 더 이상 사용할 수 없습니다. expired.meeting=미팅이 유효 기간이 만료되었습니다. diff --git a/src/test/java/com/e2i/wemeet/config/security/filter/RefreshTokenProcessingFilterTest.java b/src/test/java/com/e2i/wemeet/config/security/filter/RefreshTokenProcessingFilterTest.java index b8ad5331..ca7c58d3 100644 --- a/src/test/java/com/e2i/wemeet/config/security/filter/RefreshTokenProcessingFilterTest.java +++ b/src/test/java/com/e2i/wemeet/config/security/filter/RefreshTokenProcessingFilterTest.java @@ -21,6 +21,7 @@ import com.e2i.wemeet.support.module.AbstractIntegrationTest; import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; import com.epages.restdocs.apispec.ResourceSnippetParameters; +import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -55,7 +56,7 @@ void refresh() throws Exception { String refreshToken = refreshTokenHandler.createToken(payload); String accessToken = accessTokenHandler.createToken(payload); given(memberRepository.findRoleByMemberId(anyLong())) - .willReturn(Role.USER); + .willReturn(Optional.of(Role.USER)); ValueOperations operations = redisTemplate.opsForValue(); @@ -88,7 +89,7 @@ void refreshFail() throws Exception { String refreshToken = refreshTokenHandler.createToken(payload); String accessToken = accessTokenHandler.createToken(payload); given(memberRepository.findRoleByMemberId(anyLong())) - .willReturn(Role.USER); + .willReturn(Optional.of(Role.USER)); ValueOperations operations = redisTemplate.opsForValue(); diff --git a/src/test/java/com/e2i/wemeet/controller/meeting/MeetingControllerTest.java b/src/test/java/com/e2i/wemeet/controller/meeting/MeetingControllerTest.java index a14cbc31..2163bf20 100644 --- a/src/test/java/com/e2i/wemeet/controller/meeting/MeetingControllerTest.java +++ b/src/test/java/com/e2i/wemeet/controller/meeting/MeetingControllerTest.java @@ -4,7 +4,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willDoNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; @@ -55,10 +54,7 @@ class Request { @Test void sendMeetingRequest() throws Exception { // given - final Long memberId = 1L; final SendMeetingRequestDto request = new SendMeetingRequestDto(1L); - willDoNothing() - .given(meetingHandleService).sendRequest(request, memberId); // when ResultActions perform = mockMvc.perform(post("/v1/meeting") @@ -74,7 +70,7 @@ void sendMeetingRequest() throws Exception { jsonPath("$.message").value("Send meeting request success"), jsonPath("$.data").doesNotExist() ); - verify(meetingHandleService).sendRequest(request, memberId); + verify(meetingHandleService).sendRequest(any(), any(), any()); sendMeetingRequestWriteRestDocs(perform); } @@ -84,12 +80,9 @@ void sendMeetingRequest() throws Exception { @Test void sendMeetingRequestWithMessage() throws Exception { // given - final Long memberId = 1L; final String message = "안녕하세요!! 재밌게 놀아봐요ㅎㅎ"; final SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto( 1L, message); - willDoNothing() - .given(meetingHandleService).sendRequestWithMessage(request, memberId); // when ResultActions perform = mockMvc.perform(post("/v1/meeting/message") @@ -105,7 +98,7 @@ void sendMeetingRequestWithMessage() throws Exception { jsonPath("$.message").value("Send meeting request with message success"), jsonPath("$.data").doesNotExist() ); - verify(meetingHandleService).sendRequestWithMessage(request, memberId); + verify(meetingHandleService).sendRequestWithMessage(any(), any(), any()); sendMeetingRequestWithMessageWriteRestDocs(perform); } @@ -118,8 +111,6 @@ void sendMeetingRequestWithMessageWithLongMessages(String message) throws Except final Long memberId = 1L; final SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto( 1L, message); - willDoNothing() - .given(meetingHandleService).sendRequestWithMessage(request, memberId); // when ResultActions perform = mockMvc.perform(post("/v1/meeting/message") @@ -135,7 +126,7 @@ void sendMeetingRequestWithMessageWithLongMessages(String message) throws Except jsonPath("$.message").value("서버에서 예상치 못한 예외가 발생했습니다"), jsonPath("$.data").doesNotExist() ); - verify(meetingHandleService, times(0)).sendRequestWithMessage(request, memberId); + verify(meetingHandleService, times(0)).sendRequestWithMessage(any(), any(), any()); } public static Stream provideMessagesForMeetingRequest() { diff --git a/src/test/java/com/e2i/wemeet/controller/team/TeamControllerTest.java b/src/test/java/com/e2i/wemeet/controller/team/TeamControllerTest.java index 73c60491..026e6e87 100644 --- a/src/test/java/com/e2i/wemeet/controller/team/TeamControllerTest.java +++ b/src/test/java/com/e2i/wemeet/controller/team/TeamControllerTest.java @@ -1,5 +1,6 @@ package com.e2i.wemeet.controller.team; +import static com.e2i.wemeet.domain.meeting.data.AcceptStatus.PENDING; import static com.e2i.wemeet.support.fixture.MemberFixture.KAI; import static com.e2i.wemeet.support.fixture.TeamFixture.HONGDAE_TEAM_1; import static com.e2i.wemeet.support.fixture.TeamMemberFixture.create_3_man; @@ -33,6 +34,7 @@ import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; import com.epages.restdocs.apispec.ResourceSnippetParameters; import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -189,12 +191,12 @@ void readTeamById() throws Exception { Member kai = KAI.create_with_id(1L); List teamMembers = create_3_man(); TeamInformationDto teamInformation = TeamInformationDto.of( - HONGDAE_TEAM_1.create_with_id(kai, teamMembers, 1L)); + HONGDAE_TEAM_1.create_with_id(kai, teamMembers, 1L), 1L, 1L, PENDING); LeaderResponseDto leader = LeaderResponseDto.of(kai); List imageUrls = List.of("/v1/test1", "/v1/test2", "/v1/test3"); final TeamDetailResponseDto response = TeamDetailResponseDto.of(teamInformation, leader, imageUrls); - given(teamService.readByTeamId(anyLong(), anyLong())) + given(teamService.readByTeamId(anyLong(), anyLong(), any(LocalDateTime.class))) .willReturn(response); // when @@ -230,7 +232,7 @@ void readTeamById() throws Exception { jsonPath("$.data.leader.leaderLowProfileImageUrl").value("/v1/kai"), jsonPath("$.data.leader.imageAuth").value(false) ); - verify(teamService).readByTeamId(anyLong(), anyLong()); + verify(teamService).readByTeamId(anyLong(), anyLong(), any(LocalDateTime.class)); readByTeamIdWriteRestDocs(perform); } diff --git a/src/test/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepositoryTest.java b/src/test/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepositoryTest.java index 2107a897..28eb9dd5 100644 --- a/src/test/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepositoryTest.java +++ b/src/test/java/com/e2i/wemeet/domain/meeting/MeetingRequestRepositoryTest.java @@ -19,6 +19,7 @@ import com.e2i.wemeet.domain.team.Team; import com.e2i.wemeet.domain.team.TeamRepository; import com.e2i.wemeet.support.module.AbstractRepositoryUnitTest; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.DisplayName; @@ -77,7 +78,7 @@ void findMeetingRequestByTeamAndPartnerTeamId() { meetingRequestRepository.save(WITH_OUT_MESSAGE.create(kaiTeam, rimTeam)); // when - Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); + Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); // then assertThat(findId).isPresent(); @@ -94,7 +95,7 @@ void findMeetingRequestByTeamAndPartnerTeamIdWithoutRequest() { Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); // when - Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); + Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); // then assertThat(findId).isEmpty(); @@ -115,7 +116,7 @@ void findMeetingRequestByTeamAndPartnerTeamIdBeforeRequestExpired() { meetingRequestRepository.save(meetingRequest); // when - Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); + Optional findId = meetingRequestRepository.findIdByTeamIdAndPartnerTeamId(kaiTeam.getTeamId(), rimTeam.getTeamId()); // then assertThat(findId).isEmpty(); diff --git a/src/test/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImplTest.java b/src/test/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImplTest.java index 8c6d08eb..d5e8568a 100644 --- a/src/test/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImplTest.java +++ b/src/test/java/com/e2i/wemeet/domain/team/TeamCustomRepositoryImplTest.java @@ -1,8 +1,11 @@ package com.e2i.wemeet.domain.team; +import static com.e2i.wemeet.domain.meeting.data.AcceptStatus.ACCEPT; +import static com.e2i.wemeet.domain.meeting.data.AcceptStatus.EXPIRED; import static com.e2i.wemeet.domain.member.data.Mbti.ENFJ; import static com.e2i.wemeet.domain.member.data.Mbti.ENFP; import static com.e2i.wemeet.domain.member.data.Mbti.ESFJ; +import static com.e2i.wemeet.support.config.ReflectionUtils.setFieldValueToSuperClassField; import static com.e2i.wemeet.support.fixture.MemberFixture.KAI; import static com.e2i.wemeet.support.fixture.MemberFixture.RIM; import static com.e2i.wemeet.support.fixture.TeamFixture.HONGDAE_TEAM_1; @@ -25,6 +28,7 @@ import com.e2i.wemeet.dto.response.LeaderResponseDto; import com.e2i.wemeet.exception.notfound.TeamNotFoundException; import com.e2i.wemeet.support.module.AbstractRepositoryUnitTest; +import java.time.LocalDateTime; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -105,9 +109,10 @@ void findTeamInformationByTeamId() { //given Member kai = memberRepository.save(KAI.create(ANYANG_CODE)); Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + LocalDateTime readTime = LocalDateTime.now(); //when - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), kaiTeam.getTeamId()) + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), kaiTeam.getTeamId(), readTime) .orElseThrow(TeamNotFoundException::new); //then @@ -135,15 +140,47 @@ void findHeart() { .team(kaiTeam) .partnerTeam(rimTeam) .build()); + LocalDateTime readTime = LocalDateTime.now(); //when - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId()) + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId(), readTime) .orElseThrow(TeamNotFoundException::new); //then assertThat(teamInformation.getIsLiked()).isTrue(); } + @DisplayName("좋아요를 여러번 눌렀어도, 해당 좋아요 이력들이 유효한 기간이 지났다면 isLiked 가 false 가 된다") + @Test + void findHeartRecent() { + // given + Member kai = memberRepository.save(KAI.create(ANYANG_CODE)); + Member rim = memberRepository.save(RIM.create(WOMANS_CODE)); + Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); + Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + + Heart heart1 = heartRepository.save(Heart.builder() + .team(kaiTeam) + .partnerTeam(rimTeam) + .build()); + setFieldValueToSuperClassField(heart1, "createdAt", LocalDateTime.now().minusDays(10)); + Heart heart2 = heartRepository.save(Heart.builder() + .team(kaiTeam) + .partnerTeam(rimTeam) + .build()); + setFieldValueToSuperClassField(heart2, "createdAt", LocalDateTime.now().minusDays(11)); + LocalDateTime readTime = LocalDateTime.now(); + entityManager.flush(); + entityManager.clear(); + + //when + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId(), readTime) + .orElseThrow(TeamNotFoundException::new); + + //then + assertThat(teamInformation.getIsLiked()).isFalse(); + } + @DisplayName("미팅 신청 현황을 조회할 수 있다.") @EnumSource @ParameterizedTest @@ -159,19 +196,51 @@ void findMeetingRequestStatus(AcceptStatus acceptStatus) { .partnerTeam(rimTeam) .build(); meetingRequest.changeStatus(acceptStatus); - meetingRequestRepository.save(meetingRequest); + LocalDateTime readTime = LocalDateTime.now(); //when - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId()) + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId(), readTime) .orElseThrow(TeamNotFoundException::new); - System.out.println("teamInformation = " + teamInformation); - //then assertThat(teamInformation.getMeetingRequestStatus()).isEqualTo(acceptStatus); } + @DisplayName("가장 최신의 미팅 신청 현황을 조회할 수 있다.") + @Test + void findMeetingRequestExpired() { + // given + Member kai = memberRepository.save(KAI.create(ANYANG_CODE)); + Member rim = memberRepository.save(RIM.create(WOMANS_CODE)); + Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); + Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + + MeetingRequest meetingRequest2 = MeetingRequest.builder() + .team(kaiTeam) + .partnerTeam(rimTeam) + .build(); + meetingRequest2.changeStatus(EXPIRED); + meetingRequestRepository.save(meetingRequest2); + setFieldValueToSuperClassField(meetingRequest2, "createdAt", LocalDateTime.now().minusDays(10)); + + MeetingRequest meetingRequest = MeetingRequest.builder() + .team(kaiTeam) + .partnerTeam(rimTeam) + .build(); + meetingRequest.changeStatus(ACCEPT); + meetingRequestRepository.save(meetingRequest); + + LocalDateTime readTime = LocalDateTime.now(); + + //when + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId(), readTime) + .orElseThrow(TeamNotFoundException::new); + + //then + assertThat(teamInformation.getMeetingRequestStatus()).isEqualTo(ACCEPT); + } + @DisplayName("미팅 신청내역이 없을 경우 null이 반환된다.") @Test void findMeetingRequestStatusWithoutRequest() { @@ -180,27 +249,27 @@ void findMeetingRequestStatusWithoutRequest() { Member rim = memberRepository.save(RIM.create(WOMANS_CODE)); Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + LocalDateTime readTime = LocalDateTime.now(); //when - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId()) + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(kai.getMemberId(), rimTeam.getTeamId(), readTime) .orElseThrow(TeamNotFoundException::new); - System.out.println("teamInformation = " + teamInformation); - //then assertThat(teamInformation.getMeetingRequestStatus()).isNull(); } - @DisplayName("팀이 없어도 다른 팀 상세정보를 조회할 수 있다.") + @DisplayName("팀이 없어도 다른 팀 상세 정보를 조회할 수 있다.") @Test void findTeamInformationWithoutTeam() { // given Member kai = memberRepository.save(KAI.create(ANYANG_CODE)); Member rim = memberRepository.save(RIM.create(WOMANS_CODE)); Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + LocalDateTime readTime = LocalDateTime.now(); //when - TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(rim.getMemberId(), kaiTeam.getTeamId()) + TeamInformationDto teamInformation = teamRepository.findTeamInformationByTeamId(rim.getMemberId(), kaiTeam.getTeamId(), readTime) .orElseThrow(TeamNotFoundException::new); // then diff --git a/src/test/java/com/e2i/wemeet/redis/RedisConnectionTest.java b/src/test/java/com/e2i/wemeet/redis/RedisConnectionTest.java index 9643b6f2..12951606 100644 --- a/src/test/java/com/e2i/wemeet/redis/RedisConnectionTest.java +++ b/src/test/java/com/e2i/wemeet/redis/RedisConnectionTest.java @@ -1,7 +1,8 @@ package com.e2i.wemeet.redis; +import static org.assertj.core.api.Assertions.assertThat; + import com.e2i.wemeet.support.module.AbstractIntegrationTest; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -23,7 +24,7 @@ void load() { operation.set(key, value); String fromRedis = operation.get(key); - Assertions.assertThat(fromRedis).isEqualTo(value); + assertThat(fromRedis).isEqualTo(value); } @DisplayName("Redis 에 존재하지 않는 키값을 조회하면 Null이 반환된다.") @@ -36,6 +37,25 @@ void isNull() { operation.set(key, value); String fromRedis = operation.get("123"); - Assertions.assertThat(fromRedis).isNull(); + assertThat(fromRedis).isNull(); + } + + @DisplayName("중복된 키값을 저장하면 덮어쓰기 된다.") + @Test + void duplicate() { + // given + final String key = "01083215123"; + final String value = "123456"; + final String secondValue = "987643"; + + // when + ValueOperations operation = redisTemplate.opsForValue(); + operation.set(key, value); + operation.set(key, secondValue); + + // then + String fromRedis = operation.get(key); + assertThat(fromRedis).isEqualTo(secondValue); } + } diff --git a/src/test/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImplTest.java b/src/test/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImplTest.java index ae1ddc2d..32bcc99f 100644 --- a/src/test/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImplTest.java +++ b/src/test/java/com/e2i/wemeet/service/meeting/MeetingHandleServiceImplTest.java @@ -86,7 +86,7 @@ void sendRequest() { final int kaiCredit = kai.getCredit(); // when - meetingHandleService.sendRequest(request, kai.getMemberId()); + meetingHandleService.sendRequest(request, kai.getMemberId(), LocalDateTime.now()); // then List meetingRequests = meetingRequestRepository.findAll(); @@ -111,9 +111,10 @@ void preventDuplicateMeetingRequest() { SendMeetingRequestDto request = new SendMeetingRequestDto(rimTeam.getTeamId()); setAuthentication(kai.getMemberId(), "MANAGER"); + LocalDateTime meetingRequestTime = LocalDateTime.now(); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(DuplicateMeetingRequestException.class); MeetingRequest meetingRequest = WITH_OUT_MESSAGE.create(kaiTeam, rimTeam); @@ -140,7 +141,7 @@ void preventDuplicateMeetingRequestBeforeRequestExpired() { final int kaiCredit = kai.getCredit(); // when - meetingHandleService.sendRequest(request, kai.getMemberId()); + meetingHandleService.sendRequest(request, kai.getMemberId(), LocalDateTime.now()); // then List meetingRequests = meetingRequestRepository.findAllByTeamAndAcceptStatus(kaiTeam, PENDING); @@ -152,6 +153,37 @@ void preventDuplicateMeetingRequestBeforeRequestExpired() { assertThat(kai.getCredit()).isLessThan(kaiCredit); } + @DisplayName("미팅 신청의 유효 기간이 지났고 Pending 상태인 데이터 외의 다른 이력이 없다면 미팅을 신청할 수 있다") + @Test + void existAfterExpirationDaysPendingRequest() { + // given + Member kai = memberRepository.save(KAI.create(ANYANG_CODE)); + Member rim = memberRepository.save(RIM.create(WOMANS_CODE)); + Team kaiTeam = teamRepository.save(HONGDAE_TEAM_1.create(kai, create_3_man())); + Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); + + MeetingRequest meetingRequest = WITH_OUT_MESSAGE.create(kaiTeam, rimTeam); + meetingRequestRepository.save(meetingRequest); + final LocalDateTime meetingAcceptTime = LocalDateTime.of(2021, 8, 15, 13, 0); + ReflectionUtils.setFieldValueToSuperClassField(meetingRequest, "createdAt", meetingAcceptTime); + + SendMeetingRequestDto request = new SendMeetingRequestDto(rimTeam.getTeamId()); + setAuthentication(kai.getMemberId(), "MANAGER"); + + final int kaiCredit = kai.getCredit(); + + // when + Long meetingRequestId = meetingHandleService.sendRequest(request, kai.getMemberId(), LocalDateTime.now()); + + // then + MeetingRequest meetingRequests = meetingRequestRepository.findById(meetingRequestId) + .orElseThrow(); + assertThat(meetingRequests) + .extracting("team", "partnerTeam", "acceptStatus", "message") + .contains(kaiTeam, rimTeam, PENDING, null); + assertThat(kai.getCredit()).isLessThan(kaiCredit); + } + @DisplayName("보유하고 있는 크레딧이 부족하면 미팅을 신청할 수 없다.") @Test void sendRequestWithNotEnoughCredit() { @@ -163,10 +195,11 @@ void sendRequestWithNotEnoughCredit() { Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); SendMeetingRequestDto request = new SendMeetingRequestDto(rimTeam.getTeamId()); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(CreditNotEnoughException.class); } @@ -184,7 +217,7 @@ void sendRequestReduceCreditAfterRequest() { setAuthentication(kai.getMemberId(), "MANAGER"); // when - meetingHandleService.sendRequest(request, kai.getMemberId()); + meetingHandleService.sendRequest(request, kai.getMemberId(), LocalDateTime.now()); // then Integer findCredit = memberRepository.findCreditByMemberId(kai.getMemberId()) @@ -205,7 +238,7 @@ void sendRequestWithInvalidPartnerTeamId() { setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId(), LocalDateTime.now())) .isExactlyInstanceOf(TeamNotExistsException.class); } @@ -220,10 +253,11 @@ void sendRequestToHasBeenDeletedTeam() { rimTeam.delete(LocalDateTime.of(2023, 8, 15, 13, 0)); SendMeetingRequestDto request = new SendMeetingRequestDto(rimTeam.getTeamId()); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(TeamHasBeenDeletedException.class); } @@ -236,10 +270,11 @@ void sendResponseWithoutTeam() { Team rimTeam = teamRepository.save(HONGDAE_TEAM_1.create(rim, create_3_woman())); SendMeetingRequestDto request = new SendMeetingRequestDto(rimTeam.getTeamId()); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "USER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequest(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(UnAuthorizedRoleException.class); } @@ -262,10 +297,11 @@ void sendResponseWithMessage() { final int kaiCredit = kai.getCredit(); SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto(rimTeam.getTeamId(), message); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when - meetingHandleService.sendRequestWithMessage(request, kai.getMemberId()); + meetingHandleService.sendRequestWithMessage(request, kai.getMemberId(), meetingRequestTime); // then List meetingRequests = meetingRequestRepository.findAll(); @@ -290,10 +326,11 @@ void sendResponseWithMessageWithNotEnoughCredit() { final String message = "안녕하세요"; SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto(rimTeam.getTeamId(), message); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(CreditNotEnoughException.class); } @@ -310,10 +347,11 @@ void sendResponseWithMessageReduceCreditAfterRequest() { final String message = "안녕하세요"; SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto(rimTeam.getTeamId(), message); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when - meetingHandleService.sendRequestWithMessage(request, kai.getMemberId()); + meetingHandleService.sendRequestWithMessage(request, kai.getMemberId(), meetingRequestTime); // then Integer findCredit = memberRepository.findCreditByMemberId(kai.getMemberId()) @@ -332,10 +370,11 @@ void sendResponseWithMessageWithoutTeam() { final String message = "안녕하세요"; SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto(rimTeam.getTeamId(), message); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(TeamNotExistsException.class); } @@ -351,10 +390,11 @@ void sendResponseWithMessageWithLongMessage() { final String message = "안녕하세요 저는 ~~ 살고있는 ~~ 입니다. 저희는 높은 텐션을 가지고 있어서 재밌게 놀 수 있을 것 같아요!"; SendMeetingWithMessageRequestDto request = new SendMeetingWithMessageRequestDto(rimTeam.getTeamId(), message); + LocalDateTime meetingRequestTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when & then - assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId())) + assertThatThrownBy(() -> meetingHandleService.sendRequestWithMessage(request, kai.getMemberId(), meetingRequestTime)) .isExactlyInstanceOf(UndeclaredThrowableException.class); } diff --git a/src/test/java/com/e2i/wemeet/service/team/TeamServiceImplTest.java b/src/test/java/com/e2i/wemeet/service/team/TeamServiceImplTest.java index 3a5ea8b2..63ce31bd 100644 --- a/src/test/java/com/e2i/wemeet/service/team/TeamServiceImplTest.java +++ b/src/test/java/com/e2i/wemeet/service/team/TeamServiceImplTest.java @@ -24,6 +24,7 @@ import com.e2i.wemeet.domain.team_image.TeamImageRepository; import com.e2i.wemeet.dto.response.team.TeamDetailResponseDto; import com.e2i.wemeet.support.module.AbstractServiceTest; +import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -61,10 +62,11 @@ void readByTeamId() { .build()); teamImageRepository.saveAll(BASIC_TEAM_IMAGE.createTeamImages(kaiTeam)); + final LocalDateTime readTime = LocalDateTime.now(); setAuthentication(kai.getMemberId(), "MANAGER"); // when - TeamDetailResponseDto responseDto = teamService.readByTeamId(rim.getMemberId(), kaiTeam.getTeamId()); + TeamDetailResponseDto responseDto = teamService.readByTeamId(rim.getMemberId(), kaiTeam.getTeamId(), readTime); // then assertThat(responseDto)