From 98933b41df456f9c17bf37c21cbca696142b4d46 Mon Sep 17 00:00:00 2001 From: Eunjin3395 Date: Tue, 10 Dec 2024 16:04:15 +0900 Subject: [PATCH 1/3] =?UTF-8?q?:sparkles:=20[Feat]=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=B7=A8=EC=86=8C=20API=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 --- .../friend/controller/FriendController.java | 9 ++++++++ .../friend/service/FriendFacadeService.java | 15 ++++++++++++ .../friend/service/FriendService.java | 23 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/friend/controller/FriendController.java b/src/main/java/com/gamegoo/gamegoo_v2/friend/controller/FriendController.java index 90d310a5..141b24ff 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/friend/controller/FriendController.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/friend/controller/FriendController.java @@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -39,4 +40,12 @@ public ApiResponse acceptFriendRequest(@PathVariable(name return ApiResponse.ok(friendFacadeService.acceptFriendRequest(member, targetMemberId)); } + @Operation(summary = "친구 요청 취소 API", description = "대상 회원에게 보낸 친구 요청을 취소하는 API 입니다.") + @Parameter(name = "memberId", description = "친구 요청을 취소할 대상 회원의 id 입니다.") + @DeleteMapping("/request/{memberId}") + public ApiResponse cancelFriendRequest(@PathVariable(name = "memberId") Long targetMemberId, + @AuthMember Member member) { + return ApiResponse.ok(friendFacadeService.cancelFriendRequest(member, targetMemberId)); + } + } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendFacadeService.java index cc877091..3ce2e024 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendFacadeService.java @@ -46,4 +46,19 @@ public FriendRequestResponse acceptFriendRequest(Member member, Long targetMembe return FriendRequestResponse.of(friendRequest.getFromMember().getId(), "친구 요청 수락 성공"); } + /** + * 친구 요청 취소 Facade 메소드 + * + * @param member + * @param targetMemberId + * @return + */ + @Transactional + public FriendRequestResponse cancelFriendRequest(Member member, Long targetMemberId) { + Member targetMember = memberService.findMember(targetMemberId); + FriendRequest friendRequest = friendService.cancelFriendRequest(member, targetMember); + + return FriendRequestResponse.of(friendRequest.getToMember().getId(), "친구 요청 취소 성공"); + } + } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendService.java b/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendService.java index e24a0645..cdf6f4bf 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/friend/service/FriendService.java @@ -86,6 +86,29 @@ public FriendRequest acceptFriendRequest(Member member, Member targetMember) { return friendRequest; } + /** + * targetMember에게 보낸 친구 요청 취소 처리 메소드 + * + * @param member + * @param targetMember + * @return + */ + @Transactional + public FriendRequest cancelFriendRequest(Member member, Member targetMember) { + // targetMember로 나 자신을 요청한 경우 검증 + validateNotSelf(member, targetMember); + + // 수락 대기 상태인 FriendRequest 엔티티 조회 및 검증 + FriendRequest friendRequest = friendRequestRepository.findByFromMemberAndToMemberAndStatus(member, + targetMember, FriendRequestStatus.PENDING) + .orElseThrow(() -> new FriendException(ErrorCode.PENDING_FRIEND_REQUEST_NOT_EXIST)); + + // FriendRequest 엔티티 상태 변경 + friendRequest.updateStatus(FriendRequestStatus.CANCELLED); + + return friendRequest; + } + private void validateNotSelf(Member member, Member targetMember) { if (member.equals(targetMember)) { throw new FriendException(ErrorCode.FRIEND_BAD_REQUEST); From b9b9566ebf526b9c9ea4ab6a43670773085948b4 Mon Sep 17 00:00:00 2001 From: Eunjin3395 Date: Tue, 10 Dec 2024 16:13:28 +0900 Subject: [PATCH 2/3] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=20=EC=9A=94=EC=B2=AD=20=EC=B7=A8=EC=86=8C=20API=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/FriendFacadeServiceTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/integration/friend/FriendFacadeServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/integration/friend/FriendFacadeServiceTest.java index 62ce0025..4ae8e3ac 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/integration/friend/FriendFacadeServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/integration/friend/FriendFacadeServiceTest.java @@ -7,6 +7,7 @@ import com.gamegoo.gamegoo_v2.exception.common.ErrorCode; import com.gamegoo.gamegoo_v2.friend.domain.Friend; import com.gamegoo.gamegoo_v2.friend.domain.FriendRequest; +import com.gamegoo.gamegoo_v2.friend.domain.FriendRequestStatus; import com.gamegoo.gamegoo_v2.friend.dto.FriendRequestResponse; import com.gamegoo.gamegoo_v2.friend.repository.FriendRepository; import com.gamegoo.gamegoo_v2.friend.repository.FriendRequestRepository; @@ -217,6 +218,50 @@ void accpetFriendRequest_shouldThrowWhenNoPendingRequest() { .hasMessage(ErrorCode.PENDING_FRIEND_REQUEST_NOT_EXIST.getMessage()); } + @DisplayName("친구 요청 취소 성공") + @Test + void cancelFriendRequestSucceeds() { + // given + Member member = createMember(MEMBER_EMAIL, MEMBER_GAMENAME); + Member targetMember = createMember("target@naver.com", "target"); + + // 나 -> 상대 친구 요청 생성 + friendRequestRepository.save(FriendRequest.create(member, targetMember)); + + // when + FriendRequestResponse response = friendFacadeService.cancelFriendRequest(member, targetMember.getId()); + + // then + assertThat(response.getTargetMemberId()).isEqualTo(targetMember.getId()); + assertThat(friendRequestRepository.findByFromMemberAndToMemberAndStatus(member, targetMember, + FriendRequestStatus.CANCELLED)).isNotEmpty(); + } + + @DisplayName("친구 요청 취소 실패: 본인 id를 요청한 경우 예외가 발생한다.") + @Test + void cancelFriendRequest_shouldThrowWhenTargetIsSelf() { + // given + Member member = createMember(MEMBER_EMAIL, MEMBER_GAMENAME); + + // when // then + assertThatThrownBy(() -> friendFacadeService.cancelFriendRequest(member, member.getId())) + .isInstanceOf(FriendException.class) + .hasMessage(ErrorCode.FRIEND_BAD_REQUEST.getMessage()); + } + + @DisplayName("친구 요청 취소 실패: PENDING 상태인 친구 요청이 없는 경우 예외가 발생한다") + @Test + void cancelFriendRequest_shouldThrowWhenNoPendingRequest() { + // given + Member member = createMember(MEMBER_EMAIL, MEMBER_GAMENAME); + Member targetMember = createMember("target@naver.com", "target"); + + // when // then + assertThatThrownBy(() -> friendFacadeService.cancelFriendRequest(member, targetMember.getId())) + .isInstanceOf(FriendException.class) + .hasMessage(ErrorCode.PENDING_FRIEND_REQUEST_NOT_EXIST.getMessage()); + } + private Member createMember(String email, String gameName) { return memberRepository.save(Member.builder() .email(email) From c350bee83e3f7f0766ab47ff6f9340aa12ed2c3f Mon Sep 17 00:00:00 2001 From: Eunjin3395 Date: Tue, 10 Dec 2024 16:19:02 +0900 Subject: [PATCH 3/3] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=20=EC=9A=94=EC=B2=AD=20=EC=B7=A8=EC=86=8C=20API=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/FriendControllerTest.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/controller/friend/FriendControllerTest.java b/src/test/java/com/gamegoo/gamegoo_v2/controller/friend/FriendControllerTest.java index ea00bd8e..d3a97fea 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/controller/friend/FriendControllerTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/controller/friend/FriendControllerTest.java @@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willThrow; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -198,4 +199,55 @@ void acceptFriendRequestFailedWhenNoPendingRequest() throws Exception { } + @Nested + @DisplayName("친구 요청 취소") + class CancelFriendRequestTest { + + @DisplayName("친구 요청 취소 성공") + @Test + void cancelFriendRequestSucceeds() throws Exception { + // given + FriendRequestResponse response = FriendRequestResponse.builder() + .targetMemberId(TARGET_MEMBER_ID) + .message("친구 요청 취소 성공") + .build(); + + given(friendFacadeService.cancelFriendRequest(any(), any())).willReturn(response); + + // when // then + mockMvc.perform(delete(API_URL_PREFIX + "/request/{memberId}", TARGET_MEMBER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("OK")) + .andExpect(jsonPath("$.data.message").value("친구 요청 취소 성공")) + .andExpect(jsonPath("$.data.targetMemberId").value(TARGET_MEMBER_ID)); + } + + @DisplayName("친구 요청 취소 실패: 본인 id를 요청한 경우 에러 응답을 반환한다.") + @Test + void cancelFriendRequestFailedWhenTargetIsSelf() throws Exception { + // given + willThrow(new FriendException(ErrorCode.FRIEND_BAD_REQUEST)) + .given(friendFacadeService).cancelFriendRequest(any(), eq(TARGET_MEMBER_ID)); + + // when // then + mockMvc.perform(delete(API_URL_PREFIX + "/request/{memberId}", TARGET_MEMBER_ID)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value(ErrorCode.FRIEND_BAD_REQUEST.getMessage())); + } + + @DisplayName("친구 요청 취소 실패: PENDING 상태인 친구 요청이 없는 경우 에러 응답을 반환한다.") + @Test + void cancelFriendRequestFailedWhenNoPendingRequest() throws Exception { + // given + willThrow(new FriendException(ErrorCode.PENDING_FRIEND_REQUEST_NOT_EXIST)) + .given(friendFacadeService).cancelFriendRequest(any(), eq(TARGET_MEMBER_ID)); + + // when // then + mockMvc.perform(delete(API_URL_PREFIX + "/request/{memberId}", TARGET_MEMBER_ID)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value(ErrorCode.PENDING_FRIEND_REQUEST_NOT_EXIST.getMessage())); + } + + } + }