From 66a1ce8962cdce5cbc371822a937426380b8e4c0 Mon Sep 17 00:00:00 2001 From: Son Gahyun <77109954+hyun2371@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:07:35 +0900 Subject: [PATCH] =?UTF-8?q?[feat=20#119]=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EC=A1=B0=ED=9A=8C=20API=20(#120)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feat] : 채팅방 조회 관련 에러 코드 추가 * [style] : dto 네이밍 변경 * [feat] : 채팅방 상세조회 비즈니스 로직 작성 * [test] : 채팅방 상세조회 비즈니스 로직 테스트 * [feat] : 채팅방 상세조회 API 메서드 작성 * [test] : 채팅방 상세조회 API 통합 테스트 * [style] : 코드 리포멧팅 --- .../chat/controller/ChatRoomController.java | 10 +++ .../dnd/gongmuin/chat/dto/ChatRoomMapper.java | 14 ++-- .../dto/response/ChatRoomDetailResponse.java | 2 +- .../chat/exception/ChatErrorCode.java | 3 +- .../chat/service/ChatRoomService.java | 22 +++++- .../controller/ChatRoomControllerTest.java | 19 +++++ .../chat/service/ChatRoomServiceTest.java | 75 ++++++++++++++++++- 7 files changed, 135 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/chat/controller/ChatRoomController.java b/src/main/java/com/dnd/gongmuin/chat/controller/ChatRoomController.java index 20a65cbb..a80fad5c 100644 --- a/src/main/java/com/dnd/gongmuin/chat/controller/ChatRoomController.java +++ b/src/main/java/com/dnd/gongmuin/chat/controller/ChatRoomController.java @@ -52,6 +52,16 @@ public ResponseEntity createChatRoom( return ResponseEntity.ok(response); } + @Operation(summary = "채팅방 조회 API", description = "채팅방 아이디로 채팅방을 조회한다.") + @GetMapping("/api/chat-rooms/{chatRoomId}") + public ResponseEntity createChatRoom( + @PathVariable("chatRoomId") Long chatRoomId, + @AuthenticationPrincipal Member member + ) { + ChatRoomDetailResponse response = chatRoomService.getChatRoomById(chatRoomId, member); + return ResponseEntity.ok(response); + } + @Operation(summary = "채팅 수락 API", description = "채팅방에서 요청자와의 채팅을 수락한다.") @PatchMapping("/api/chat-rooms/{chatRoomId}/accept") public ResponseEntity acceptChat( diff --git a/src/main/java/com/dnd/gongmuin/chat/dto/ChatRoomMapper.java b/src/main/java/com/dnd/gongmuin/chat/dto/ChatRoomMapper.java index 620083d8..49edf58a 100644 --- a/src/main/java/com/dnd/gongmuin/chat/dto/ChatRoomMapper.java +++ b/src/main/java/com/dnd/gongmuin/chat/dto/ChatRoomMapper.java @@ -26,19 +26,21 @@ public static ChatRoom toChatRoom( ); } - public static ChatRoomDetailResponse toChatRoomDetailResponse(ChatRoom chatRoom) { + public static ChatRoomDetailResponse toChatRoomDetailResponse( + ChatRoom chatRoom, + Member chatPartner + ) { QuestionPost questionPost = chatRoom.getQuestionPost(); - Member answerer = chatRoom.getAnswerer(); // 요청자만 채팅방 생성 가능 -> 상태방: 답변자 return new ChatRoomDetailResponse( questionPost.getId(), questionPost.getJobGroup().getLabel(), questionPost.getTitle(), new MemberInfo( - answerer.getId(), - answerer.getNickname(), - answerer.getJobGroup().getLabel(), - answerer.getProfileImageNo() + chatPartner.getId(), + chatPartner.getNickname(), + chatPartner.getJobGroup().getLabel(), + chatPartner.getProfileImageNo() ), chatRoom.getStatus().getLabel() ); diff --git a/src/main/java/com/dnd/gongmuin/chat/dto/response/ChatRoomDetailResponse.java b/src/main/java/com/dnd/gongmuin/chat/dto/response/ChatRoomDetailResponse.java index e59a481b..5a40eab7 100644 --- a/src/main/java/com/dnd/gongmuin/chat/dto/response/ChatRoomDetailResponse.java +++ b/src/main/java/com/dnd/gongmuin/chat/dto/response/ChatRoomDetailResponse.java @@ -7,6 +7,6 @@ public record ChatRoomDetailResponse( String targetJobGroup, String title, MemberInfo receiverInfo, - String status + String chatStatus ) { } diff --git a/src/main/java/com/dnd/gongmuin/chat/exception/ChatErrorCode.java b/src/main/java/com/dnd/gongmuin/chat/exception/ChatErrorCode.java index f266e085..20c74094 100644 --- a/src/main/java/com/dnd/gongmuin/chat/exception/ChatErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/chat/exception/ChatErrorCode.java @@ -12,7 +12,8 @@ public enum ChatErrorCode implements ErrorCode { INVALID_MESSAGE_TYPE("메시지 타입을 올바르게 입력해주세요.", "CH_001"), NOT_FOUND_CHAT_ROOM("해당 아이디의 채팅방이 존재하지 않습니다.", "CH_002"), UNAUTHORIZED_REQUEST("채팅 수락을 하거나 거절할 권한이 없습니다.", "CH_003"), - UNABLE_TO_CHANGE_CHAT_STATUS("이미 수락했거나 거절한 요청입니다.", "CH_004"); + UNABLE_TO_CHANGE_CHAT_STATUS("이미 수락했거나 거절한 요청입니다.", "CH_004"), + UNAUTHORIZED_CHAT_ROOM("권한이 없는 채팅방입니다", "CH_005"); private final String message; private final String code; diff --git a/src/main/java/com/dnd/gongmuin/chat/service/ChatRoomService.java b/src/main/java/com/dnd/gongmuin/chat/service/ChatRoomService.java index 24343e53..1008ed00 100644 --- a/src/main/java/com/dnd/gongmuin/chat/service/ChatRoomService.java +++ b/src/main/java/com/dnd/gongmuin/chat/service/ChatRoomService.java @@ -59,10 +59,20 @@ public ChatRoomDetailResponse createChatRoom(CreateChatRoomRequest request, Memb QuestionPost questionPost = getQuestionPostById(request.questionPostId()); Member answerer = getMemberById(request.answererId()); return ChatRoomMapper.toChatRoomDetailResponse( - chatRoomRepository.save(ChatRoomMapper.toChatRoom(questionPost, inquirer, answerer)) + chatRoomRepository.save( + ChatRoomMapper.toChatRoom(questionPost, inquirer, answerer) + ), + answerer ); } + @Transactional(readOnly = true) + public ChatRoomDetailResponse getChatRoomById(Long chatRoomId, Member member) { + ChatRoom chatRoom = getChatRoomById(chatRoomId); + Member chatPartner = getChatPartner(member.getId(), chatRoom); + return ChatRoomMapper.toChatRoomDetailResponse(chatRoom, chatPartner); + } + @Transactional public AcceptChatResponse acceptChat(Long chatRoomId, Member member) { ChatRoom chatRoom = getChatRoomById(chatRoomId); @@ -95,5 +105,15 @@ private Member getMemberById(Long id) { return memberRepository.findById(id) .orElseThrow(() -> new NotFoundException(MemberErrorCode.NOT_FOUND_MEMBER)); } + + private Member getChatPartner(Long memberId, ChatRoom chatRoom) { + if (Objects.equals(chatRoom.getAnswerer().getId(), memberId)) { + return chatRoom.getInquirer(); + } else if (Objects.equals(chatRoom.getInquirer().getId(), memberId)) { + return chatRoom.getAnswerer(); + } else { + throw new ValidationException(ChatErrorCode.UNAUTHORIZED_CHAT_ROOM); + } + } } diff --git a/src/test/java/com/dnd/gongmuin/chat/controller/ChatRoomControllerTest.java b/src/test/java/com/dnd/gongmuin/chat/controller/ChatRoomControllerTest.java index 9626c9cb..de61ba91 100644 --- a/src/test/java/com/dnd/gongmuin/chat/controller/ChatRoomControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/chat/controller/ChatRoomControllerTest.java @@ -81,6 +81,25 @@ void createChatRoom() throws Exception { .andExpect(status().isOk()); } + @DisplayName("[채팅방 아이디로 채팅방을 상세조회할 수 있다.]") + @Test + void getChatRoomById() throws Exception { + Member inquirer = memberRepository.save(MemberFixture.member4()); + QuestionPost questionPost = questionPostRepository.save(QuestionPostFixture.questionPost(inquirer)); + ChatRoom chatRoom = chatRoomRepository.save(ChatRoomFixture.chatRoom(questionPost, inquirer, loginMember)); + + mockMvc.perform(get("/api/chat-rooms/{chatRoomId}", chatRoom.getId()) + .cookie(accessToken)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.questionPostId").value(questionPost.getId())) + .andExpect(jsonPath("$.targetJobGroup").value(questionPost.getJobGroup().getLabel())) + .andExpect(jsonPath("$.title").value(questionPost.getTitle())) + .andExpect(jsonPath("$.receiverInfo.memberId").value(inquirer.getId())) + .andExpect(jsonPath("$.receiverInfo.nickname").value(inquirer.getNickname())) + .andExpect(jsonPath("$.receiverInfo.memberJobGroup").value(inquirer.getJobGroup().getLabel())) + .andExpect(jsonPath("$.receiverInfo.profileImageNo").value(inquirer.getProfileImageNo())); + } + @DisplayName("[답변자가 채팅 요청을 수락할 수 있다.]") @Test void acceptChatRoom() throws Exception { diff --git a/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java b/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java index 55ecee1a..ddf00f78 100644 --- a/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java @@ -25,6 +25,7 @@ import com.dnd.gongmuin.chat.dto.response.ChatMessageResponse; import com.dnd.gongmuin.chat.dto.response.ChatRoomDetailResponse; import com.dnd.gongmuin.chat.dto.response.RejectChatResponse; +import com.dnd.gongmuin.chat.exception.ChatErrorCode; import com.dnd.gongmuin.chat.repository.ChatMessageRepository; import com.dnd.gongmuin.chat.repository.ChatRoomRepository; import com.dnd.gongmuin.common.exception.runtime.ValidationException; @@ -38,7 +39,7 @@ import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; -@DisplayName("[채팅방 메시지 서비스 단위 테스트]") +@DisplayName("[채팅방 서비스 단위 테스트]") @ExtendWith(MockitoExtension.class) class ChatRoomServiceTest { @@ -130,6 +131,78 @@ void createChatRoom_fail() { .hasMessageContaining(MemberErrorCode.NOT_ENOUGH_CREDIT.getMessage()); } + @DisplayName("[요청자가 채팅방 아이디로 채팅방을 조회할 수 있다.]") + @Test + void getChatRoomById_Inquirer() { + //given + Long chatRoomId = 1L; + Member inquirer = MemberFixture.member(1L); + Member answerer = MemberFixture.member(2L); + QuestionPost questionPost = QuestionPostFixture.questionPost(inquirer); + ChatRoom chatRoom = ChatRoomFixture.chatRoom(questionPost, inquirer, answerer); + + given(chatRoomRepository.findById(chatRoomId)) + .willReturn(Optional.of(chatRoom)); + + //when + ChatRoomDetailResponse response + = chatRoomService.getChatRoomById(chatRoomId, inquirer); + + //then + assertAll( + () -> assertThat(response.questionPostId()) + .isEqualTo(questionPost.getId()), + () -> assertThat(response.receiverInfo().memberId()) + .isEqualTo(answerer.getId()) + ); + } + + @DisplayName("[답변자가 채팅방 아이디로 채팅방을 조회할 수 있다.]") + @Test + void getChatRoomById_Answerer() { + //given + Long chatRoomId = 1L; + Member inquirer = MemberFixture.member(1L); + Member answerer = MemberFixture.member(2L); + QuestionPost questionPost = QuestionPostFixture.questionPost(inquirer); + ChatRoom chatRoom = ChatRoomFixture.chatRoom(questionPost, inquirer, answerer); + + given(chatRoomRepository.findById(chatRoomId)) + .willReturn(Optional.of(chatRoom)); + + //when + ChatRoomDetailResponse response + = chatRoomService.getChatRoomById(chatRoomId, answerer); + + //then + assertAll( + () -> assertThat(response.questionPostId()) + .isEqualTo(questionPost.getId()), + () -> assertThat(response.receiverInfo().memberId()) + .isEqualTo(inquirer.getId()) + ); + } + + @DisplayName("[채팅방에 속하지 않은 사람은 채팅방을 조회할 수 없다.]") + @Test + void getChatRoomById_Unauthorized() { + //given + Long chatRoomId = 1L; + Member inquirer = MemberFixture.member(1L); + Member answerer = MemberFixture.member(2L); + Member unrelatedMember = MemberFixture.member(3L); + QuestionPost questionPost = QuestionPostFixture.questionPost(inquirer); + ChatRoom chatRoom = ChatRoomFixture.chatRoom(questionPost, inquirer, answerer); + + given(chatRoomRepository.findById(chatRoomId)) + .willReturn(Optional.of(chatRoom)); + + //when & then + assertThatThrownBy(() -> chatRoomService.getChatRoomById(chatRoomId, unrelatedMember)) + .isInstanceOf(ValidationException.class) + .hasMessageContaining(ChatErrorCode.UNAUTHORIZED_CHAT_ROOM.getMessage()); + } + @DisplayName("[답변자가 채팅 요청을 수락할 수 있다.]") @Test void acceptChat() {