Skip to content

Commit

Permalink
[feat #119] 채팅방 상세조회 API (#120)
Browse files Browse the repository at this point in the history
* [feat] : 채팅방 조회 관련 에러 코드 추가

* [style] : dto 네이밍 변경

* [feat] : 채팅방 상세조회 비즈니스 로직 작성

* [test] : 채팅방 상세조회 비즈니스 로직 테스트

* [feat] : 채팅방 상세조회 API 메서드 작성

* [test] : 채팅방 상세조회 API 통합 테스트

* [style] : 코드 리포멧팅
  • Loading branch information
hyun2371 authored Sep 27, 2024
1 parent 3855069 commit 66a1ce8
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ public ResponseEntity<ChatRoomDetailResponse> createChatRoom(
return ResponseEntity.ok(response);
}

@Operation(summary = "채팅방 조회 API", description = "채팅방 아이디로 채팅방을 조회한다.")
@GetMapping("/api/chat-rooms/{chatRoomId}")
public ResponseEntity<ChatRoomDetailResponse> 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<AcceptChatResponse> acceptChat(
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/com/dnd/gongmuin/chat/dto/ChatRoomMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public record ChatRoomDetailResponse(
String targetJobGroup,
String title,
MemberInfo receiverInfo,
String status
String chatStatus
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 21 additions & 1 deletion src/main/java/com/dnd/gongmuin/chat/service/ChatRoomService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit 66a1ce8

Please sign in to comment.