diff --git a/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java b/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java index 7577930c..76259afa 100644 --- a/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java +++ b/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java @@ -26,4 +26,6 @@ public interface AnswerRepository extends JpaRepository { @Query("select a from Answer a " + "join fetch a.member where a.id = :answerId") Optional findByIdWithMember(Long answerId); + + boolean existsByQuestionPostIdAndMember(Long questionPostId, Member member); } \ No newline at end of file diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/exception/ChatInquiryErrorCode.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/exception/ChatInquiryErrorCode.java index d3d239f9..f7a27e1a 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/exception/ChatInquiryErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/exception/ChatInquiryErrorCode.java @@ -12,7 +12,8 @@ public enum ChatInquiryErrorCode implements ErrorCode { NOT_FOUND_INQUIRY("해당 아이디의 채팅 요청이 존재하지 않습니다.", "CI_001"), UNAUTHORIZED_REQUEST("채팅 요청을 수락을 하거나 거절할 권한이 없습니다.", "CI_002"), UNABLE_TO_CHANGE_STATUS("이미 수락했거나 거절한 요청입니다.", "CI_003"), - NOT_FOUND_STATUS("채팅방 상태값을 올바르게 입력해주세요.", "CI_004"); + NOT_FOUND_STATUS("채팅방 상태값을 올바르게 입력해주세요.", "CI_004"), + NOT_EXISTS_ANSWERER("해당 아이디의 답변자가 해당 게시글에 존재하지 않습니다.", "CI_005"); private final String message; private final String code; diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryService.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryService.java index 091bc0d2..73259149 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryService.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryService.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.dnd.gongmuin.answer.repository.AnswerRepository; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.chat_inquiry.dto.AcceptChatResponse; import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryDetailResponse; @@ -54,16 +55,19 @@ public class ChatInquiryService { private final CreditHistoryService creditHistoryService; private final ApplicationEventPublisher eventPublisher; private final ChatMessageRepository chatMessageRepository; + private final AnswerRepository answerRepository; @Transactional public CreateChatInquiryResponse createChatInquiry(CreateChatInquiryRequest request, Member inquirer) { QuestionPost questionPost = getQuestionPostById(request.questionPostId()); Member answerer = getMemberById(request.answererId()); + validateChatAnswerer(request.questionPostId(), answerer); ChatInquiry chatInquiry = chatInquiryRepository.save( ChatInquiryMapper.toChatInquiry(questionPost, inquirer, answerer, request.inquiryMessage()) ); - memberRepository.save(inquirer); - creditHistoryService.saveCreditHistory(CreditType.CHAT_REQUEST, CHAT_REWARD, inquirer); + + saveInquirerCreditHistory(inquirer); + eventPublisher.publishEvent( new NotificationEvent(NotificationType.CHAT_REQUEST, chatInquiry.getId(), inquirer.getId(), answerer) ); @@ -140,6 +144,17 @@ public void rejectChatAuto() { autoRejectedChatInquiryNotification(rejectedChatInquiryDtos); } + private void validateChatAnswerer(Long questionPostId, Member answerer) { + if (!answerRepository.existsByQuestionPostIdAndMember(questionPostId, answerer)) { + throw new ValidationException(ChatInquiryErrorCode.NOT_EXISTS_ANSWERER); + } + } + + private void saveInquirerCreditHistory(Member inquirer) { + memberRepository.save(inquirer); + creditHistoryService.saveCreditHistory(CreditType.CHAT_REQUEST, CHAT_REWARD, inquirer); + } + private List getRejectedInquirerIds(List rejectedChatInquiryDtos) { return rejectedChatInquiryDtos.stream() .map(dto -> dto.inquirer().getId()) diff --git a/src/test/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryControllerTest.java b/src/test/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryControllerTest.java index cc98553c..e141c2d8 100644 --- a/src/test/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryControllerTest.java @@ -12,12 +12,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import com.dnd.gongmuin.answer.repository.AnswerRepository; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryRequest; import com.dnd.gongmuin.chat_inquiry.repository.ChatInquiryRepository; import com.dnd.gongmuin.chatroom.repository.ChatMessageRepository; import com.dnd.gongmuin.chatroom.repository.ChatRoomRepository; +import com.dnd.gongmuin.common.fixture.AnswerFixture; import com.dnd.gongmuin.common.fixture.ChatInquiryFixture; import com.dnd.gongmuin.common.fixture.MemberFixture; import com.dnd.gongmuin.common.fixture.QuestionPostFixture; @@ -43,6 +45,9 @@ class ChatInquiryControllerTest extends ApiTestSupport { @Autowired private QuestionPostRepository questionPostRepository; + @Autowired + private AnswerRepository answerRepository; + @Autowired private ChatRoomRepository chatRoomRepository; @@ -57,6 +62,7 @@ void teardown() { creditHistoryRepository.deleteAll(); memberRepository.deleteAll(); questionPostRepository.deleteAll(); + answerRepository.deleteAll(); chatInquiryRepository.deleteAll(); chatRoomRepository.deleteAll(); chatMessageRepository.deleteAll(); @@ -69,11 +75,14 @@ void createChatInquiry() throws Exception { int previousCredit = loginMember.getCredit(); Member answerer = memberRepository.save(MemberFixture.member5()); QuestionPost questionPost = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); + answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); + CreateChatInquiryRequest request = new CreateChatInquiryRequest( questionPost.getId(), answerer.getId(), INQUIRY_MESSAGE ); + //when & then mockMvc.perform(post("/api/chat/inquiries") .cookie(accessToken) diff --git a/src/test/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryServiceTest.java b/src/test/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryServiceTest.java index b2d2758b..2c4fd3e6 100644 --- a/src/test/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/chat_inquiry/service/ChatInquiryServiceTest.java @@ -18,6 +18,7 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.test.util.ReflectionTestUtils; +import com.dnd.gongmuin.answer.repository.AnswerRepository; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; import com.dnd.gongmuin.chat_inquiry.dto.AcceptChatResponse; @@ -27,6 +28,7 @@ import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryResponse; import com.dnd.gongmuin.chat_inquiry.dto.RejectChatResponse; import com.dnd.gongmuin.chat_inquiry.dto.RejectedChatInquiryDto; +import com.dnd.gongmuin.chat_inquiry.exception.ChatInquiryErrorCode; import com.dnd.gongmuin.chat_inquiry.repository.ChatInquiryRepository; import com.dnd.gongmuin.chatroom.domain.ChatRoom; import com.dnd.gongmuin.chatroom.repository.ChatMessageRepository; @@ -65,6 +67,9 @@ class ChatInquiryServiceTest { @Mock private QuestionPostRepository questionPostRepository; + @Mock + private AnswerRepository answerRepository; + @Mock private ApplicationEventPublisher eventPublisher; @@ -98,6 +103,8 @@ void createInquiry() { .willReturn(Optional.of(questionPost)); given(memberRepository.findById(answerer.getId())) .willReturn(Optional.of(answerer)); + given(answerRepository.existsByQuestionPostIdAndMember(questionPost.getId(), answerer)) + .willReturn(true); given(chatInquiryRepository.save(any(ChatInquiry.class))).willReturn(chatInquiry); CreateChatInquiryResponse response = chatInquiryService.createChatInquiry(request, inquirer); @@ -129,6 +136,8 @@ void createInquiry_fails() { .willReturn(Optional.of(questionPost)); given(memberRepository.findById(answerer.getId())) .willReturn(Optional.of(answerer)); + given(answerRepository.existsByQuestionPostIdAndMember(questionPost.getId(), answerer)) + .willReturn(true); //when & then assertThatThrownBy(() -> chatInquiryService.createChatInquiry(request, inquirer)) @@ -136,6 +145,33 @@ void createInquiry_fails() { .hasMessageContaining(MemberErrorCode.NOT_ENOUGH_CREDIT.getMessage()); } + @DisplayName("[질문 게시글에 답변을 하지 않은 회원에게 채팅 신청할 수 없다.]") + @Test + void createChatInquiry_fails2() { + //given + Member inquirer = MemberFixture.member(1L); + Member answerer = MemberFixture.member(2L); + ReflectionTestUtils.setField(inquirer, "credit", CHAT_REWARD); + QuestionPost questionPost = QuestionPostFixture.questionPost(inquirer); + CreateChatInquiryRequest request = new CreateChatInquiryRequest( + questionPost.getId(), + answerer.getId(), + INQUIRY_MESSAGE + ); + + given(questionPostRepository.findById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); + given(memberRepository.findById(answerer.getId())) + .willReturn(Optional.of(answerer)); + given(answerRepository.existsByQuestionPostIdAndMember(questionPost.getId(), answerer)) + .willReturn(false); + + //when & then + assertThatThrownBy(() -> chatInquiryService.createChatInquiry(request, inquirer)) + .isInstanceOf(ValidationException.class) + .hasMessageContaining(ChatInquiryErrorCode.NOT_EXISTS_ANSWERER.getMessage()); + } + @DisplayName("[채팅 요청 아이디로 채팅 요청 상세를 조회할 수 있다.]") @Test void getChatInquiryById() {