From a9c2c43c8107a142eb3198b6542d74c5d551e6a8 Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 16:26:14 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[test]=20:=20=EC=B1=84=ED=83=9D=20?= =?UTF-8?q?=EC=8B=9C=20=ED=81=AC=EB=A0=88=EB=94=A7=20=EC=A0=95=ED=95=A9?= =?UTF-8?q?=EC=84=B1=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 --- .../answer/service/AnswerServiceTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java index a1e18c38..be3578af 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -4,8 +4,12 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.BDDMockito.*; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -172,4 +176,55 @@ void chooseAnswer_fail2() { .isInstanceOf(ValidationException.class) .hasMessageContaining(QuestionPostErrorCode.NOT_AUTHORIZED.getMessage()); } + + @DisplayName("[동시간대에 100명의 사용자에게 입금을 받는다.]") + @Test + void creditHistoryWithOneHundred() throws Exception { + // given + final long threadCount = 10_000L; + final int writerCredit = 10_000_000; + ExecutorService executorService = Executors.newFixedThreadPool(32); + CountDownLatch latch = new CountDownLatch((int)threadCount); + + Member writer = MemberFixture.member(1L); + Member answer = MemberFixture.member(2L); + ReflectionTestUtils.setField(writer, "credit", writerCredit); + ReflectionTestUtils.setField(answer, "credit", 0); + + List questionPosts = new ArrayList<>(); + List answers = new ArrayList<>(); + + for (long i = 1L; i <= threadCount; i++) { + QuestionPost questionPost = QuestionPostFixture.questionPost(i, writer); + + Answer answer1 = AnswerFixture.answer(questionPost.getId(), answer); + ReflectionTestUtils.setField(answer1, "id", i); + questionPosts.add(questionPost); + answers.add(answer1); + + given(answerRepository.findById(i)).willReturn(Optional.of(answer1)); + given(questionPostRepository.findById(questionPost.getId())).willReturn(Optional.of(questionPost)); + } + + // when + long startTime = System.currentTimeMillis(); + for (long i = 0L; i < threadCount; i++) { + final int index = (int)i; + executorService.submit(() -> { + try { + answerService.chooseAnswer(answers.get(index).getId(), writer); + } finally { + latch.countDown(); + } + }); + } + latch.await(); + + long endTime = System.currentTimeMillis(); + + System.out.println("Execution time: " + (endTime - startTime) + " ms"); + + // then + assertEquals(answer.getCredit(), writerCredit); + } } \ No newline at end of file From af9e50cc49578abd8d09caad5f2bd00e9149eb52 Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 17:08:13 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[feat]=20:=20QuestionPostSimpleQueryRepo?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fetch join을 활용한 한방 쿼리 추가 --- .../QuestionPostSimpleQueryRepository.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostSimpleQueryRepository.java diff --git a/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostSimpleQueryRepository.java b/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostSimpleQueryRepository.java new file mode 100644 index 00000000..01120751 --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostSimpleQueryRepository.java @@ -0,0 +1,28 @@ +package com.dnd.gongmuin.question_post.repository; + +import java.util.Optional; + +import org.springframework.stereotype.Repository; + +import com.dnd.gongmuin.question_post.domain.QuestionPost; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; + +@Repository +@RequiredArgsConstructor +public class QuestionPostSimpleQueryRepository { + + private final EntityManager em; + + public Optional findQuestionPostById(Long questionPostId) { + QuestionPost questionPost = em.createQuery( + "select q from QuestionPost q" + + " join fetch q.member m" + + " where q.id = :questionPostId", QuestionPost.class + ) + .setParameter("questionPostId", questionPostId) + .getSingleResult(); + return Optional.of(questionPost); + } +} From e47ae40f4026ccf196000f88b9307564d3de4f66 Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 17:09:00 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[feat]=20:=20AnswerSimpleQueryRepo=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fetch join을 활용한 한방 쿼리 추가 --- .../AnswerSimpleQueryRepository.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/answer/repository/AnswerSimpleQueryRepository.java diff --git a/src/main/java/com/dnd/gongmuin/answer/repository/AnswerSimpleQueryRepository.java b/src/main/java/com/dnd/gongmuin/answer/repository/AnswerSimpleQueryRepository.java new file mode 100644 index 00000000..53bc7419 --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/answer/repository/AnswerSimpleQueryRepository.java @@ -0,0 +1,28 @@ +package com.dnd.gongmuin.answer.repository; + +import java.util.Optional; + +import org.springframework.stereotype.Repository; + +import com.dnd.gongmuin.answer.domain.Answer; + +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; + +@Repository +@RequiredArgsConstructor +public class AnswerSimpleQueryRepository { + + private final EntityManager em; + + public Optional findAnswerById(Long answerId) { + Answer answer = em.createQuery( + "select a from Answer a" + + " join fetch a.member m" + + " where a.id = :answerId", Answer.class + ) + .setParameter("answerId", answerId) + .getSingleResult(); + return Optional.of(answer); + } +} From c710df348ce20405c62288d6284be4a76220f40d Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 18:00:33 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=EC=B1=84?= =?UTF-8?q?=ED=83=9D=20=EC=BF=BC=EB=A6=AC=20=EA=B0=9C=EC=88=98=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20v2=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/service/AnswerService.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java index 81b7ef7e..264af6a8 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -13,6 +13,7 @@ import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; import com.dnd.gongmuin.answer.exception.AnswerErrorCode; import com.dnd.gongmuin.answer.repository.AnswerRepository; +import com.dnd.gongmuin.answer.repository.AnswerSimpleQueryRepository; import com.dnd.gongmuin.common.dto.PageMapper; import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.common.exception.runtime.NotFoundException; @@ -23,6 +24,7 @@ import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; +import com.dnd.gongmuin.question_post.repository.QuestionPostSimpleQueryRepository; import lombok.RequiredArgsConstructor; @@ -34,6 +36,8 @@ public class AnswerService { private final AnswerRepository answerRepository; private final CreditHistoryService creditHistoryService; private final ApplicationEventPublisher eventPublisher; + private final QuestionPostSimpleQueryRepository questionPostSimpleQueryRepository; + private final AnswerSimpleQueryRepository answerSimpleQueryRepository; private static void validateIfQuestioner(Member member, QuestionPost questionPost) { if (!questionPost.isQuestioner(member.getId())) { @@ -85,6 +89,23 @@ public AnswerDetailResponse chooseAnswer( return AnswerMapper.toAnswerDetailResponse(answer); } + @Transactional + public AnswerDetailResponse chooseAnswerV2( + Long answerId, + Member member + ) { + Answer answer = getAnswerByIdV2(answerId); + QuestionPost questionPost = findQuestionPostByIdV2(answer.getQuestionPostId()); + validateIfQuestioner(member, questionPost); + chooseAnswer(questionPost, answer); + + eventPublisher.publishEvent(new NotificationEvent( + CHOSEN, questionPost.getId(), member.getId(), answer.getMember() + )); + + return AnswerMapper.toAnswerDetailResponse(answer); + } + private void chooseAnswer(QuestionPost questionPost, Answer answer) { questionPost.updateIsChosen(answer); answer.getMember().increaseCredit(questionPost.getReward()); @@ -108,4 +129,14 @@ private QuestionPost findQuestionPostById(Long questionPostId) { return questionPostRepository.findById(questionPostId) .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); } + + private Answer getAnswerByIdV2(Long answerId) { + return answerSimpleQueryRepository.findAnswerById(answerId) + .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); + } + + private QuestionPost findQuestionPostByIdV2(Long questionPostId) { + return questionPostSimpleQueryRepository.findQuestionPostById(questionPostId) + .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); + } } \ No newline at end of file From 9d4b53b52a10f654ce59bbe234e035eea9cd84b3 Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 18:00:54 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=EC=B1=84?= =?UTF-8?q?=ED=83=9D=20=EC=BF=BC=EB=A6=AC=20=EA=B0=9C=EC=88=98=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20v2=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/controller/AnswerController.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java index ddd2913f..2f15c3cd 100644 --- a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java +++ b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java @@ -52,10 +52,21 @@ public ResponseEntity> getAnswersByQuestionPo @ApiResponse(useReturnTypeSchema = true) @PostMapping("/api/question-posts/answers/{answerId}") public ResponseEntity getAnswersByQuestionPostId( - @PathVariable Long answerId, + @PathVariable("answerId") Long answerId, @AuthenticationPrincipal Member member ) { AnswerDetailResponse response = answerService.chooseAnswer(answerId, member); return ResponseEntity.ok(response); } + + @Operation(summary = "답변 채택 API", description = "질문자가 답변을 채택한다.") + @ApiResponse(useReturnTypeSchema = true) + @PostMapping("/api/v2/question-posts/answers/{answerId}") + public ResponseEntity getAnswersByQuestionPostIdV2( + @PathVariable("answerId") Long answerId, + @AuthenticationPrincipal Member member + ) { + AnswerDetailResponse response = answerService.chooseAnswerV2(answerId, member); + return ResponseEntity.ok(response); + } } From ee91d7264b88081a83dc91590e90d825eadcfb8a Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 18:02:21 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[test]=20:=20=EB=8B=B5=EB=B3=80=EC=B1=84?= =?UTF-8?q?=ED=83=9D=20=EC=BF=BC=EB=A6=AC=20=EA=B0=9C=EC=88=98=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20v2=20=EB=8B=A8=EC=9C=84=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/service/AnswerServiceTest.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java index be3578af..fedc50b5 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -28,6 +28,7 @@ import com.dnd.gongmuin.answer.dto.AnswerDetailResponse; import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; import com.dnd.gongmuin.answer.repository.AnswerRepository; +import com.dnd.gongmuin.answer.repository.AnswerSimpleQueryRepository; import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.common.fixture.AnswerFixture; @@ -40,6 +41,7 @@ import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; +import com.dnd.gongmuin.question_post.repository.QuestionPostSimpleQueryRepository; @DisplayName("[AnswerService 테스트]") @ExtendWith(MockitoExtension.class) @@ -50,9 +52,15 @@ class AnswerServiceTest { @Mock private QuestionPostRepository questionPostRepository; + @Mock + private QuestionPostSimpleQueryRepository questionPostSimpleQueryRepository; + @Mock private AnswerRepository answerRepository; + @Mock + private AnswerSimpleQueryRepository answerSimpleQueryRepository; + @Mock private CreditHistoryService creditHistoryService; @@ -134,6 +142,27 @@ void chooseAnswer() { Assertions.assertThat(response.isChosen()).isTrue(); } + @DisplayName("[답변을 채택할 수 있다.]") + @Test + void chooseAnswerV2() { + //given + Long questionPostId = 1L; + Member member = MemberFixture.member(1L); + QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); + Answer answer = AnswerFixture.answer(1L, questionPostId); + + given(answerSimpleQueryRepository.findAnswerById(answer.getId())) + .willReturn(Optional.of(answer)); + given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); + + //when + AnswerDetailResponse response = answerService.chooseAnswerV2(answer.getId(), member); + + //then + Assertions.assertThat(response.isChosen()).isTrue(); + } + @DisplayName("[크레딧이 부족하면 답변을 채택할 수 없다.]") @Test void chooseAnswer_fail() { @@ -177,7 +206,7 @@ void chooseAnswer_fail2() { .hasMessageContaining(QuestionPostErrorCode.NOT_AUTHORIZED.getMessage()); } - @DisplayName("[동시간대에 100명의 사용자에게 입금을 받는다.]") + @DisplayName("[동시에 10_000개의 채택이 일어나 크레딧을 입금 받는다.]") @Test void creditHistoryWithOneHundred() throws Exception { // given @@ -221,7 +250,6 @@ void creditHistoryWithOneHundred() throws Exception { latch.await(); long endTime = System.currentTimeMillis(); - System.out.println("Execution time: " + (endTime - startTime) + " ms"); // then From 18b9c6ebf814c445cf797d60210e5193968d3375 Mon Sep 17 00:00:00 2001 From: dudxo Date: Thu, 21 Nov 2024 18:10:45 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[test]=20:=20=EB=8B=B5=EB=B3=80=EC=B1=84?= =?UTF-8?q?=ED=83=9D=20=EC=BF=BC=EB=A6=AC=20=EA=B0=9C=EC=88=98=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20v2=20=ED=86=B5=ED=95=A9=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AnswerControllerTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java index d8888bb9..0eb74ef2 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -125,6 +125,7 @@ void chooseAnswer() throws Exception { = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); Member answerer = memberRepository.save(MemberFixture.member2()); Answer answer = answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); + long startTime = System.currentTimeMillis(); mockMvc.perform(post("/api/question-posts/answers/{answerId}", answer.getId()) .cookie(accessToken) @@ -137,5 +138,31 @@ void chooseAnswer() throws Exception { .andExpect(jsonPath("$.memberInfo.nickname").value(answerer.getNickname())) .andExpect(jsonPath("$.memberInfo.memberJobGroup").value(answerer.getJobGroup().getLabel()) ); + long endTime = System.currentTimeMillis(); + System.out.println("Execution time: " + (endTime - startTime) + " ms"); + } + + @DisplayName("[질문자는 답변을 채택할 수 있다.V2]") + @Test + void chooseAnswerV2() throws Exception { + QuestionPost questionPost + = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); + Member answerer = memberRepository.save(MemberFixture.member2()); + Answer answer = answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); + long startTime = System.currentTimeMillis(); + + mockMvc.perform(post("/api/v2/question-posts/answers/{answerId}", answer.getId()) + .cookie(accessToken) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.content").value(answer.getContent())) + .andExpect(jsonPath("$.isChosen").value(true)) + .andExpect(jsonPath("$.isQuestioner").value(false)) + .andExpect(jsonPath("$.memberInfo.memberId").value(answerer.getId())) + .andExpect(jsonPath("$.memberInfo.nickname").value(answerer.getNickname())) + .andExpect(jsonPath("$.memberInfo.memberJobGroup").value(answerer.getJobGroup().getLabel()) + ); + long endTime = System.currentTimeMillis(); + System.out.println("Execution time: " + (endTime - startTime) + " ms"); } } \ No newline at end of file From e08aedf3ca0401f47ec8c083df6c6ff653ab8ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=81=ED=83=9C?= <56019823+dudxo@users.noreply.github.com> Date: Thu, 21 Nov 2024 22:16:31 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[=08Refactor=20#151]=20JWT=20Subject=20?= =?UTF-8?q?=EA=B0=9C=EC=9D=B8=EC=A0=95=EB=B3=B4=20=EC=A0=9C=EA=B1=B0=20(#1?= =?UTF-8?q?54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [refactor] JWT 생성 로직 변경 - JWT 생성시 subject에 개인정보(이메일)이 아닌 PK값이 들어가도록 변경 - 검증 토큰을 이용한 인증 객체 생성 시 subject 이메일 -> PK 변경에 따라 PK로 회원 찾도록 변경 * [refactor] : 토큰 generate 메서드 파라미터 변경으로 인한 리팩토링 * [refactor] : 토큰 generate 메서드 파라미터 변경으로 인한 리팩토링 * [refactor] : 토큰 generate 메서드 파라미터 변경으로 인한 리팩토링 --- .../dnd/gongmuin/auth/service/AuthService.java | 14 +++++++------- .../handler/CustomOauth2SuccessHandler.java | 4 ++-- .../security/jwt/util/TokenProvider.java | 16 ++++++++-------- .../auth/controller/AuthControllerTest.java | 2 +- .../gongmuin/auth/service/AuthServiceTest.java | 14 ++++++++++---- .../gongmuin/common/support/ApiTestSupport.java | 4 ++-- .../gongmuin/security/jwt/TokenProviderTest.java | 14 +++++++------- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/auth/service/AuthService.java b/src/main/java/com/dnd/gongmuin/auth/service/AuthService.java index 43106ca5..d0236181 100644 --- a/src/main/java/com/dnd/gongmuin/auth/service/AuthService.java +++ b/src/main/java/com/dnd/gongmuin/auth/service/AuthService.java @@ -74,13 +74,13 @@ public TempSignResponse tempSignUp(TempSignUpRequest tempSignUpRequest, HttpServ throw new NotFoundException(MemberErrorCode.NOT_FOUND_MEMBER); } - memberRepository.save(member); + Member savedMember = memberRepository.save(member); AuthInfo authInfo = AuthInfo.of(member.getSocialName(), member.getSocialEmail(), member.getRole()); CustomOauth2User customOauth2User = new CustomOauth2User(authInfo); - tokenProvider.generateRefreshToken(customOauth2User, now); - String accessToken = tokenProvider.generateAccessToken(customOauth2User, now); + tokenProvider.generateRefreshToken(savedMember, customOauth2User, now); + String accessToken = tokenProvider.generateAccessToken(savedMember, customOauth2User, now); response.addCookie(cookieUtil.createCookie(accessToken)); return new TempSignResponse(true); @@ -98,8 +98,8 @@ public TempSignResponse tempSignIn(TempSignInRequest tempSignInRequest, HttpServ AuthInfo authInfo = AuthInfo.of(member.getSocialName(), member.getSocialEmail(), member.getRole()); CustomOauth2User customOauth2User = new CustomOauth2User(authInfo); - tokenProvider.generateRefreshToken(customOauth2User, now); - String accessToken = tokenProvider.generateAccessToken(customOauth2User, now); + tokenProvider.generateRefreshToken(member, customOauth2User, now); + String accessToken = tokenProvider.generateAccessToken(member, customOauth2User, now); response.addCookie(cookieUtil.createCookie(accessToken)); return new TempSignResponse(true); @@ -175,8 +175,8 @@ public ReissueResponse reissue(HttpServletRequest request, HttpServletResponse r CustomOauth2User customUser = new CustomOauth2User( AuthInfo.of(member.getSocialName(), member.getSocialEmail(), member.getRole())); - String reissuedAccessToken = tokenProvider.generateAccessToken(customUser, new Date()); - tokenProvider.generateRefreshToken(customUser, new Date()); + String reissuedAccessToken = tokenProvider.generateAccessToken(member, customUser, new Date()); + tokenProvider.generateRefreshToken(member, customUser, new Date()); response.addCookie(cookieUtil.createCookie(reissuedAccessToken)); diff --git a/src/main/java/com/dnd/gongmuin/security/handler/CustomOauth2SuccessHandler.java b/src/main/java/com/dnd/gongmuin/security/handler/CustomOauth2SuccessHandler.java index 8a7a6a33..cc44d4e4 100644 --- a/src/main/java/com/dnd/gongmuin/security/handler/CustomOauth2SuccessHandler.java +++ b/src/main/java/com/dnd/gongmuin/security/handler/CustomOauth2SuccessHandler.java @@ -42,8 +42,8 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo Member findmember = memberRepository.findBySocialEmail(socialEmail) .orElseThrow(() -> new NotFoundException(MemberErrorCode.NOT_FOUND_MEMBER)); - String token = tokenProvider.generateAccessToken(customOauth2User, new Date()); - tokenProvider.generateRefreshToken(customOauth2User, new Date()); + String token = tokenProvider.generateAccessToken(findmember, customOauth2User, new Date()); + tokenProvider.generateRefreshToken(findmember, customOauth2User, new Date()); response.addCookie(cookieUtil.createCookie(token)); diff --git a/src/main/java/com/dnd/gongmuin/security/jwt/util/TokenProvider.java b/src/main/java/com/dnd/gongmuin/security/jwt/util/TokenProvider.java index fd4e25bc..c6fa454c 100644 --- a/src/main/java/com/dnd/gongmuin/security/jwt/util/TokenProvider.java +++ b/src/main/java/com/dnd/gongmuin/security/jwt/util/TokenProvider.java @@ -54,12 +54,12 @@ private void initSecretKey() { this.secretKey = Keys.hmacShaKeyFor(key.getBytes()); } - public String generateAccessToken(CustomOauth2User authentication, Date now) { - return generateToken(authentication, ACCESS_TOKEN_EXPIRE_TIME, now); + public String generateAccessToken(Member findMember, CustomOauth2User authentication, Date now) { + return generateToken(findMember, authentication, ACCESS_TOKEN_EXPIRE_TIME, now); } - public String generateRefreshToken(CustomOauth2User authentication, Date now) { - String refreshToken = generateToken(authentication, REFRESH_TOKEN_EXPIRE_TIME, now); + public String generateRefreshToken(Member findMember, CustomOauth2User authentication, Date now) { + String refreshToken = generateToken(findMember, authentication, REFRESH_TOKEN_EXPIRE_TIME, now); // redis Refresh 저장 redisUtil.setValues("RT:" + authentication.getEmail(), refreshToken, @@ -67,12 +67,12 @@ public String generateRefreshToken(CustomOauth2User authentication, Date now) { return refreshToken; } - private String generateToken(CustomOauth2User authentication, long tokenExpireTime, Date now) { + private String generateToken(Member findMember, CustomOauth2User authentication, long tokenExpireTime, Date now) { Date expiredTime = createExpiredDateWithTokenType(now, tokenExpireTime); String authorities = getAuthorities(authentication); return Jwts.builder() - .subject(authentication.getEmail()) + .subject(String.valueOf(findMember.getId())) .claim(ROLE_KEY, authorities) .issuedAt(now) .expiration(expiredTime) @@ -94,8 +94,8 @@ public Authentication getAuthentication(String token) { Claims claims = parseToken(token); List authorities = getAuthorities(claims); - String socialEmail = claims.getSubject(); - Member principal = memberRepository.findBySocialEmail(socialEmail) + String subject = claims.getSubject(); + Member principal = memberRepository.findById(Long.valueOf(subject)) .orElseThrow(() -> new NotFoundException(MemberErrorCode.NOT_FOUND_MEMBER)); return new UsernamePasswordAuthenticationToken(principal, token, authorities); diff --git a/src/test/java/com/dnd/gongmuin/auth/controller/AuthControllerTest.java b/src/test/java/com/dnd/gongmuin/auth/controller/AuthControllerTest.java index af976938..1a66656d 100644 --- a/src/test/java/com/dnd/gongmuin/auth/controller/AuthControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/auth/controller/AuthControllerTest.java @@ -102,7 +102,7 @@ void signUp() throws Exception { savedMember.getSocialEmail(), savedMember.getRole() ); - String token = tokenProvider.generateAccessToken(new CustomOauth2User(authInfo), new Date()); + String token = tokenProvider.generateAccessToken(savedMember, new CustomOauth2User(authInfo), new Date()); this.loginMember = savedMember; this.accessToken = new Cookie("Authorization", token); diff --git a/src/test/java/com/dnd/gongmuin/auth/service/AuthServiceTest.java b/src/test/java/com/dnd/gongmuin/auth/service/AuthServiceTest.java index 41a4d086..58754cf0 100644 --- a/src/test/java/com/dnd/gongmuin/auth/service/AuthServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/auth/service/AuthServiceTest.java @@ -174,10 +174,16 @@ void reissue() { given(cookieUtil.createCookie(anyString())).willReturn(new Cookie("Authorization", "reissueToken")); given(tokenProvider.getAuthentication(anyString())).willReturn(authentication); given(redisUtil.getValues(anyString())).willReturn("refreshToken"); - given(tokenProvider.generateAccessToken(any(CustomOauth2User.class), any(Date.class))).willReturn( - "reissueToken"); - given(tokenProvider.generateRefreshToken(any(CustomOauth2User.class), any(Date.class))).willReturn( - "reissueToken"); + given(tokenProvider.generateAccessToken( + any(Member.class), + any(CustomOauth2User.class), + any(Date.class))) + .willReturn("reissueToken"); + given(tokenProvider.generateRefreshToken( + any(Member.class), + any(CustomOauth2User.class), + any(Date.class))) + .willReturn("reissueToken"); // when ReissueResponse response = authService.reissue(mockRequest, mockResponse); diff --git a/src/test/java/com/dnd/gongmuin/common/support/ApiTestSupport.java b/src/test/java/com/dnd/gongmuin/common/support/ApiTestSupport.java index 95ba1283..cafb82f5 100644 --- a/src/test/java/com/dnd/gongmuin/common/support/ApiTestSupport.java +++ b/src/test/java/com/dnd/gongmuin/common/support/ApiTestSupport.java @@ -54,8 +54,8 @@ public void setUpMember() { savedMember.getSocialEmail(), savedMember.getRole() ); - String token = tokenProvider.generateAccessToken(new CustomOauth2User(authInfo), new Date()); - tokenProvider.generateRefreshToken(new CustomOauth2User(authInfo), new Date()); + String token = tokenProvider.generateAccessToken(savedMember, new CustomOauth2User(authInfo), new Date()); + tokenProvider.generateRefreshToken(savedMember, new CustomOauth2User(authInfo), new Date()); this.loginMember = savedMember; this.accessToken = cookieUtil.createCookie(token); } diff --git a/src/test/java/com/dnd/gongmuin/security/jwt/TokenProviderTest.java b/src/test/java/com/dnd/gongmuin/security/jwt/TokenProviderTest.java index 7dcd84d0..b15ca57e 100644 --- a/src/test/java/com/dnd/gongmuin/security/jwt/TokenProviderTest.java +++ b/src/test/java/com/dnd/gongmuin/security/jwt/TokenProviderTest.java @@ -66,7 +66,7 @@ void generateAccessToken() { CustomOauth2User authentication = new CustomOauth2User(authInfo); // when - String accessToken = tokenProvider.generateAccessToken(authentication, now); + String accessToken = tokenProvider.generateAccessToken(MemberFixture.member(1L), authentication, now); Claims claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(accessToken).getPayload(); Date expiration = claims.getExpiration(); @@ -85,7 +85,7 @@ void generateRefreshToken() { CustomOauth2User authentication = new CustomOauth2User(authInfo); // when - String accessToken = tokenProvider.generateRefreshToken(authentication, now); + String accessToken = tokenProvider.generateRefreshToken(MemberFixture.member(1L), authentication, now); Claims claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(accessToken).getPayload(); Date expiration = claims.getExpiration(); @@ -93,17 +93,17 @@ void generateRefreshToken() { assertThat(expiration.getTime()).isCloseTo(expectedExpirationTime, within(1000L)); } - @DisplayName("토큰 파싱을 통해 만들어진 인증 객체의 이메일은 토큰 정보의 이메일 값과 동일하다.") + @DisplayName("토큰 파싱을 통해 만들어진 인증 객체의 이메일은 회원 이메일과 동일하다.") @Test void getAuthentication() { // given Date now = new Date(); - Member member = MemberFixture.member(); + Member member = MemberFixture.member(1L); CustomOauth2User customOauth2User = new CustomOauth2User(authInfo); - String accessToken = tokenProvider.generateAccessToken(customOauth2User, now); + String accessToken = tokenProvider.generateAccessToken(member, customOauth2User, now); - given(memberRepository.findBySocialEmail(anyString())).willReturn(Optional.ofNullable(member)); + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(member)); // when Authentication authentication = tokenProvider.getAuthentication(accessToken); @@ -121,7 +121,7 @@ void validateToken() { Date past = new Date(124, 6, 30, 16, 0, 0); CustomOauth2User customOauth2User = new CustomOauth2User(authInfo); - String accessToken = tokenProvider.generateRefreshToken(customOauth2User, past); + String accessToken = tokenProvider.generateRefreshToken(MemberFixture.member(1L), customOauth2User, past); // when boolean result = tokenProvider.validateToken(accessToken, new Date()); From e145d22d9d091fd5512b17be9fcd6bc00191d6a8 Mon Sep 17 00:00:00 2001 From: Son Gahyun <77109954+hyun2371@users.noreply.github.com> Date: Sat, 23 Nov 2024 13:43:53 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[refactor=20#156]=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EB=AA=A9=EB=A1=9D=20API=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EC=B1=84=ED=8C=85=20=ED=8C=8C=ED=8A=B8=EB=84=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20(#157)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feat] : 채팅 요청에 createdAt 필드 추가 * [feat] : 채팅 요청 테스트 픽스쳐에 createdAt 추가 * [feat] : 채팅 파트너 구하는 로직 DTO에 추가 * [refactor] : 채팅 파트너 구하는 로직 DTO로 이동 * [style] : 코드 리포멧팅 * [test] : createdAt 포함된 testFixture 사용 --- .../chat_inquiry/dto/ChatInquiryResponse.java | 41 ++++++++++--------- .../ChatInquiryQueryRepositoryImpl.java | 22 +--------- .../service/ChatInquiryServiceTest.java | 6 +-- .../common/fixture/ChatInquiryFixture.java | 3 ++ 4 files changed, 29 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java index 87bdb0e9..7e827ae7 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java @@ -1,7 +1,7 @@ package com.dnd.gongmuin.chat_inquiry.dto; -import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; -import com.dnd.gongmuin.member.domain.JobGroup; +import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; +import com.dnd.gongmuin.member.domain.Member; import com.dnd.gongmuin.question_post.dto.response.MemberInfo; import com.querydsl.core.annotations.QueryProjection; @@ -10,30 +10,31 @@ public record ChatInquiryResponse( String inquiryMessage, String inquiryStatus, boolean isInquirer, - MemberInfo chatPartner + MemberInfo chatPartner, + String createdAt ) { @QueryProjection public ChatInquiryResponse( - Long chatInquiryId, - String inquiryMessage, - InquiryStatus inquiryStatus, - boolean isInquirer, - Long partnerId, - String partnerNickname, - JobGroup partnerJobGroup, - int partnerProfileImageNo + ChatInquiry chatInquiry, + boolean isInquirer ) { this( - chatInquiryId, - inquiryMessage, - inquiryStatus.getLabel(), + chatInquiry.getId(), + chatInquiry.getMessage(), + chatInquiry.getStatus().getLabel(), isInquirer, - new MemberInfo( - partnerId, - partnerNickname, - partnerJobGroup.getLabel(), - partnerProfileImageNo - ) + createPartnerInfo(isInquirer, chatInquiry), + chatInquiry.getCreatedAt().toString() + ); + } + + private static MemberInfo createPartnerInfo(boolean isInquirer, ChatInquiry chatInquiry) { + Member partner = isInquirer ? chatInquiry.getAnswerer() : chatInquiry.getInquirer(); + return new MemberInfo( + partner.getId(), + partner.getNickname(), + partner.getJobGroup().getLabel(), + partner.getProfileImageNo() ); } } diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/repository/ChatInquiryQueryRepositoryImpl.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/repository/ChatInquiryQueryRepositoryImpl.java index 0510d2df..b8fa741a 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/repository/ChatInquiryQueryRepositoryImpl.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/repository/ChatInquiryQueryRepositoryImpl.java @@ -26,29 +26,11 @@ public class ChatInquiryQueryRepositoryImpl implements ChatInquiryQueryRepositor public Slice getChatInquiresByMember(Member member, Pageable pageable) { List content = queryFactory .select(new QChatInquiryResponse( - chatInquiry.id, - chatInquiry.message, - chatInquiry.status, + chatInquiry, new CaseBuilder() .when(chatInquiry.inquirer.id.eq(member.getId())) .then(true) - .otherwise(false), - new CaseBuilder() - .when(chatInquiry.inquirer.id.eq(member.getId())) - .then(chatInquiry.answerer.id) - .otherwise(chatInquiry.inquirer.id), - new CaseBuilder() - .when(chatInquiry.inquirer.id.eq(member.getId())) - .then(chatInquiry.answerer.nickname) - .otherwise(chatInquiry.inquirer.nickname), - new CaseBuilder() - .when(chatInquiry.inquirer.id.eq(member.getId())) - .then(chatInquiry.answerer.jobGroup) - .otherwise(chatInquiry.inquirer.jobGroup), - new CaseBuilder() - .when(chatInquiry.inquirer.id.eq(member.getId())) - .then(chatInquiry.answerer.profileImageNo) - .otherwise(chatInquiry.inquirer.profileImageNo) + .otherwise(false) )) .from(chatInquiry) .where(chatInquiry.inquirer.id.eq(member.getId()) 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 632bc320..7ec73484 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 @@ -141,10 +141,10 @@ void getChatInquiresByMember() { Long chatInquiryId = 1L; Member targetMember = MemberFixture.member(1L); Member partner = MemberFixture.member(2L); - ChatInquiryResponse chatInquiryResponse = new ChatInquiryResponse( - chatInquiryId, INQUIRY_MESSAGE, InquiryStatus.PENDING, true, partner.getId(), - partner.getNickname(), partner.getJobGroup(), partner.getProfileImageNo() + ChatInquiry chatInquiry = ChatInquiryFixture.chatInquiry( + 1L, QuestionPostFixture.questionPost(targetMember), targetMember, partner, INQUIRY_MESSAGE ); + ChatInquiryResponse chatInquiryResponse = new ChatInquiryResponse(chatInquiry, true); given(chatInquiryRepository.getChatInquiresByMember(targetMember, pageRequest)) .willReturn(new SliceImpl<>(List.of(chatInquiryResponse), pageRequest, false)); diff --git a/src/test/java/com/dnd/gongmuin/common/fixture/ChatInquiryFixture.java b/src/test/java/com/dnd/gongmuin/common/fixture/ChatInquiryFixture.java index 4cd9a170..e9ce9079 100644 --- a/src/test/java/com/dnd/gongmuin/common/fixture/ChatInquiryFixture.java +++ b/src/test/java/com/dnd/gongmuin/common/fixture/ChatInquiryFixture.java @@ -1,5 +1,7 @@ package com.dnd.gongmuin.common.fixture; +import java.time.LocalDateTime; + import org.springframework.test.util.ReflectionTestUtils; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; @@ -40,6 +42,7 @@ public static ChatInquiry chatInquiry( message ); ReflectionTestUtils.setField(chatInquiry, "id", id); + ReflectionTestUtils.setField(chatInquiry, "createdAt", LocalDateTime.now()); return chatInquiry; } } From ca844e8ab33973021cf7f9063f455fdd91c1ad7c Mon Sep 17 00:00:00 2001 From: dudxo Date: Sat, 23 Nov 2024 16:42:46 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[refactor]=20:=20V1,=20V2=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/controller/AnswerController.java | 11 ------- .../answer/service/AnswerService.java | 29 +------------------ 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java index 2f15c3cd..799b5986 100644 --- a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java +++ b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java @@ -58,15 +58,4 @@ public ResponseEntity getAnswersByQuestionPostId( AnswerDetailResponse response = answerService.chooseAnswer(answerId, member); return ResponseEntity.ok(response); } - - @Operation(summary = "답변 채택 API", description = "질문자가 답변을 채택한다.") - @ApiResponse(useReturnTypeSchema = true) - @PostMapping("/api/v2/question-posts/answers/{answerId}") - public ResponseEntity getAnswersByQuestionPostIdV2( - @PathVariable("answerId") Long answerId, - @AuthenticationPrincipal Member member - ) { - AnswerDetailResponse response = answerService.chooseAnswerV2(answerId, member); - return ResponseEntity.ok(response); - } } diff --git a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java index 264af6a8..cc15591c 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -89,23 +89,6 @@ public AnswerDetailResponse chooseAnswer( return AnswerMapper.toAnswerDetailResponse(answer); } - @Transactional - public AnswerDetailResponse chooseAnswerV2( - Long answerId, - Member member - ) { - Answer answer = getAnswerByIdV2(answerId); - QuestionPost questionPost = findQuestionPostByIdV2(answer.getQuestionPostId()); - validateIfQuestioner(member, questionPost); - chooseAnswer(questionPost, answer); - - eventPublisher.publishEvent(new NotificationEvent( - CHOSEN, questionPost.getId(), member.getId(), answer.getMember() - )); - - return AnswerMapper.toAnswerDetailResponse(answer); - } - private void chooseAnswer(QuestionPost questionPost, Answer answer) { questionPost.updateIsChosen(answer); answer.getMember().increaseCredit(questionPost.getReward()); @@ -121,21 +104,11 @@ private void validateIfQuestionPostExists(Long questionPostId) { } private Answer getAnswerById(Long answerId) { - return answerRepository.findById(answerId) - .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); - } - - private QuestionPost findQuestionPostById(Long questionPostId) { - return questionPostRepository.findById(questionPostId) - .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); - } - - private Answer getAnswerByIdV2(Long answerId) { return answerSimpleQueryRepository.findAnswerById(answerId) .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); } - private QuestionPost findQuestionPostByIdV2(Long questionPostId) { + private QuestionPost findQuestionPostById(Long questionPostId) { return questionPostSimpleQueryRepository.findQuestionPostById(questionPostId) .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); } From 97f30effa1f8df1219dbaee92539798709442107 Mon Sep 17 00:00:00 2001 From: dudxo Date: Sat, 23 Nov 2024 16:43:26 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[test]=20:=20V1,=20V2=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AnswerControllerTest.java | 24 ------------------- .../answer/service/AnswerServiceTest.java | 21 ---------------- 2 files changed, 45 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java index 0eb74ef2..9cccbc84 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -141,28 +141,4 @@ void chooseAnswer() throws Exception { long endTime = System.currentTimeMillis(); System.out.println("Execution time: " + (endTime - startTime) + " ms"); } - - @DisplayName("[질문자는 답변을 채택할 수 있다.V2]") - @Test - void chooseAnswerV2() throws Exception { - QuestionPost questionPost - = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); - Member answerer = memberRepository.save(MemberFixture.member2()); - Answer answer = answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); - long startTime = System.currentTimeMillis(); - - mockMvc.perform(post("/api/v2/question-posts/answers/{answerId}", answer.getId()) - .cookie(accessToken) - ) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.content").value(answer.getContent())) - .andExpect(jsonPath("$.isChosen").value(true)) - .andExpect(jsonPath("$.isQuestioner").value(false)) - .andExpect(jsonPath("$.memberInfo.memberId").value(answerer.getId())) - .andExpect(jsonPath("$.memberInfo.nickname").value(answerer.getNickname())) - .andExpect(jsonPath("$.memberInfo.memberJobGroup").value(answerer.getJobGroup().getLabel()) - ); - long endTime = System.currentTimeMillis(); - System.out.println("Execution time: " + (endTime - startTime) + " ms"); - } } \ No newline at end of file diff --git a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java index fedc50b5..23e8f52e 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -142,27 +142,6 @@ void chooseAnswer() { Assertions.assertThat(response.isChosen()).isTrue(); } - @DisplayName("[답변을 채택할 수 있다.]") - @Test - void chooseAnswerV2() { - //given - Long questionPostId = 1L; - Member member = MemberFixture.member(1L); - QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); - Answer answer = AnswerFixture.answer(1L, questionPostId); - - given(answerSimpleQueryRepository.findAnswerById(answer.getId())) - .willReturn(Optional.of(answer)); - given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) - .willReturn(Optional.of(questionPost)); - - //when - AnswerDetailResponse response = answerService.chooseAnswerV2(answer.getId(), member); - - //then - Assertions.assertThat(response.isChosen()).isTrue(); - } - @DisplayName("[크레딧이 부족하면 답변을 채택할 수 없다.]") @Test void chooseAnswer_fail() { From 26bfa0493a1f09dfb344a0ab196a24c51e08e41a Mon Sep 17 00:00:00 2001 From: Son Gahyun <77109954+hyun2371@users.noreply.github.com> Date: Sat, 23 Nov 2024 17:24:16 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[feat=20#158]=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?API=20(#159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feat] : 채팅 요청 상세 조회 응답 추가 * [feat] : 채팅 요청 상세 조회 비즈니스 로직 추가 * [feat] : 채팅 요청 상세 조회 비즈니스 로직 테스트 * [feat] : 채팅 요청 상세 조회 API 메서드 추가 * [test] : 채팅 요청 상세 조회 API 메서드 테스트 * [feat] : 채팅 요청 API pk 필드명 수정 * [rename] : memberInfo DTO 위치 이동 * [remove] : 불필요한 예외 로직 처리 삭제 * [refactor] : 채팅 파트너 구하는 로직 도메인으로 이동 * [refactor] : 채팅 파트너 구하는 로직 mapper가 아닌 서비스 내에서 호출 * [style] : 코드 리포멧팅 * [style] : 줄바꿈 취소 --- .../answer/dto/AnswerDetailResponse.java | 2 +- .../dnd/gongmuin/answer/dto/AnswerMapper.java | 2 +- .../controller/ChatInquiryController.java | 13 ++++++++- .../chat_inquiry/domain/ChatInquiry.java | 10 ++++++- .../dto/ChatInquiryDetailResponse.java | 12 +++++++++ .../chat_inquiry/dto/ChatInquiryMapper.java | 20 +++++++++++++- .../chat_inquiry/dto/ChatInquiryResponse.java | 4 ++- .../dto/CreateChatInquiryResponse.java | 2 +- .../service/ChatInquiryService.java | 12 +++++++++ .../gongmuin/chatroom/domain/ChatRoom.java | 8 ++++++ .../gongmuin/chatroom/dto/ChatRoomMapper.java | 6 ++--- .../dto/response/ChatRoomDetailResponse.java | 2 +- .../dto/response/ChatRoomSimpleResponse.java | 2 +- .../chatroom/exception/ChatErrorCode.java | 3 +-- .../chatroom/service/ChatRoomService.java | 19 +++++-------- .../dto/response/MemberInfo.java | 2 +- .../question_post/dto/QuestionPostMapper.java | 2 +- .../response/QuestionPostDetailResponse.java | 2 ++ .../RegisterQuestionPostResponse.java | 2 ++ .../chat/service/ChatRoomServiceTest.java | 22 --------------- .../controller/ChatInquiryControllerTest.java | 27 +++++++++++++++++++ .../service/ChatInquiryServiceTest.java | 21 +++++++++++++-- 22 files changed, 142 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryDetailResponse.java rename src/main/java/com/dnd/gongmuin/{question_post => member}/dto/response/MemberInfo.java (67%) diff --git a/src/main/java/com/dnd/gongmuin/answer/dto/AnswerDetailResponse.java b/src/main/java/com/dnd/gongmuin/answer/dto/AnswerDetailResponse.java index fa09a159..dc74d5da 100644 --- a/src/main/java/com/dnd/gongmuin/answer/dto/AnswerDetailResponse.java +++ b/src/main/java/com/dnd/gongmuin/answer/dto/AnswerDetailResponse.java @@ -1,6 +1,6 @@ package com.dnd.gongmuin.answer.dto; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; +import com.dnd.gongmuin.member.dto.response.MemberInfo; public record AnswerDetailResponse( Long answerId, diff --git a/src/main/java/com/dnd/gongmuin/answer/dto/AnswerMapper.java b/src/main/java/com/dnd/gongmuin/answer/dto/AnswerMapper.java index b6187fb1..5738fae7 100644 --- a/src/main/java/com/dnd/gongmuin/answer/dto/AnswerMapper.java +++ b/src/main/java/com/dnd/gongmuin/answer/dto/AnswerMapper.java @@ -2,7 +2,7 @@ import com.dnd.gongmuin.answer.domain.Answer; import com.dnd.gongmuin.member.domain.Member; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryController.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryController.java index 4ee2e0e4..c9818a41 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryController.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/controller/ChatInquiryController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController; import com.dnd.gongmuin.chat_inquiry.dto.AcceptChatResponse; +import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryDetailResponse; import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryResponse; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryRequest; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryResponse; @@ -42,7 +43,17 @@ public ResponseEntity createChatInquiry( return ResponseEntity.ok(response); } - @Operation(summary = "채팅방 요청 목록 조회 API", description = "회원의 채팅방 목록을 조회한다.") + @Operation(summary = "채팅 요청 상세 조회 API", description = "채팅방 요청을 조회한다.") + @GetMapping("/api/chat/inquiries/{chatInquiryId}") + public ResponseEntity getChatInquiryById( + @PathVariable("chatInquiryId") Long chatInquiryId, + @AuthenticationPrincipal Member member + ) { + ChatInquiryDetailResponse response = chatInquiryService.getChatInquiryById(chatInquiryId, member); + return ResponseEntity.ok(response); + } + + @Operation(summary = "채팅 요청 목록 조회 API", description = "회원의 채팅 목록을 조회한다.") @GetMapping("/api/chat/inquiries") public ResponseEntity> getChatInquiresByMember( @AuthenticationPrincipal Member member, diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/domain/ChatInquiry.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/domain/ChatInquiry.java index 378b4bf6..2b905042 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/domain/ChatInquiry.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/domain/ChatInquiry.java @@ -31,7 +31,7 @@ public class ChatInquiry extends TimeBaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "chat_proposal_id", nullable = false) + @Column(name = "chat_inquiry_id", nullable = false) private Long id; @ManyToOne(fetch = LAZY) @@ -90,4 +90,12 @@ public void updateStatusRejected() { status = InquiryStatus.REJECTED; inquirer.increaseCredit(CHAT_REWARD); } + + public boolean isInquirer(Member member) { + return member.equals(this.inquirer); + } + + public Member getChatPartner(Member member) { + return isInquirer(member) ? this.answerer : this.inquirer; + } } diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryDetailResponse.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryDetailResponse.java new file mode 100644 index 00000000..08aba1a3 --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryDetailResponse.java @@ -0,0 +1,12 @@ +package com.dnd.gongmuin.chat_inquiry.dto; + +import com.dnd.gongmuin.member.dto.response.MemberInfo; + +public record ChatInquiryDetailResponse( + Long chatInquiryId, + String inquiryMessage, + String inquiryStatus, + boolean isInquirer, + MemberInfo chatPartner +) { +} diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryMapper.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryMapper.java index 4a3486ec..6e55d9de 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryMapper.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryMapper.java @@ -4,8 +4,8 @@ import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; import com.dnd.gongmuin.chatroom.domain.ChatRoom; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.dnd.gongmuin.question_post.domain.QuestionPost; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -44,6 +44,24 @@ public static CreateChatInquiryResponse toCreateChatInquiryResponse( ); } + public static ChatInquiryDetailResponse toChatInquiryDetailResponse( + ChatInquiry chatInquiry, + Member chatPartner, + boolean isInquirer + ) { + return new ChatInquiryDetailResponse(chatInquiry.getId(), + chatInquiry.getMessage(), + chatInquiry.getStatus().getLabel(), + isInquirer, + new MemberInfo( + chatPartner.getId(), + chatPartner.getNickname(), + chatPartner.getJobGroup().getLabel(), + chatPartner.getProfileImageNo() + ) + ); + } + public static AcceptChatResponse toAcceptChatResponse( ChatInquiry chatInquiry, ChatRoom chatRoom diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java index 7e827ae7..384bc5f8 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java @@ -1,8 +1,10 @@ package com.dnd.gongmuin.chat_inquiry.dto; +import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; +import com.dnd.gongmuin.member.domain.JobGroup; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.member.domain.Member; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; import com.querydsl.core.annotations.QueryProjection; public record ChatInquiryResponse( diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/CreateChatInquiryResponse.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/CreateChatInquiryResponse.java index 24080f16..cb77519d 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/CreateChatInquiryResponse.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/CreateChatInquiryResponse.java @@ -1,6 +1,6 @@ package com.dnd.gongmuin.chat_inquiry.dto; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; +import com.dnd.gongmuin.member.dto.response.MemberInfo; public record CreateChatInquiryResponse( Long chatInquiryId, 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 db7e13c8..44f2db35 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 @@ -11,6 +11,7 @@ import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.chat_inquiry.dto.AcceptChatResponse; +import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryDetailResponse; import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryMapper; import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryResponse; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryRequest; @@ -70,6 +71,17 @@ public CreateChatInquiryResponse createChatInquiry(CreateChatInquiryRequest requ return ChatInquiryMapper.toCreateChatInquiryResponse(chatInquiry); } + @Transactional(readOnly = true) + public ChatInquiryDetailResponse getChatInquiryById(Long chatInquiryId, Member member) { + ChatInquiry chatInquiry = getChatInquiryById(chatInquiryId); + + return ChatInquiryMapper.toChatInquiryDetailResponse( + chatInquiry, + chatInquiry.getChatPartner(member), + chatInquiry.isInquirer(member) + ); + } + @Transactional(readOnly = true) public PageResponse getChatInquiresByMember(Member member, Pageable pageable) { Slice responsePage = chatInquiryRepository.getChatInquiresByMember( diff --git a/src/main/java/com/dnd/gongmuin/chatroom/domain/ChatRoom.java b/src/main/java/com/dnd/gongmuin/chatroom/domain/ChatRoom.java index 97a6be8c..9fa16197 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/domain/ChatRoom.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/domain/ChatRoom.java @@ -58,4 +58,12 @@ public static ChatRoom of( ) { return new ChatRoom(questionPost, inquirer, answerer); } + + public boolean isInquirer(Member member) { + return member.equals(this.inquirer); + } + + public Member getChatPartner(Member member) { + return isInquirer(member) ? this.answerer : this.inquirer; + } } diff --git a/src/main/java/com/dnd/gongmuin/chatroom/dto/ChatRoomMapper.java b/src/main/java/com/dnd/gongmuin/chatroom/dto/ChatRoomMapper.java index 7f7eb957..58e21e0c 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/dto/ChatRoomMapper.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/dto/ChatRoomMapper.java @@ -6,8 +6,8 @@ import com.dnd.gongmuin.chatroom.dto.response.ChatRoomSimpleResponse; import com.dnd.gongmuin.chatroom.dto.response.LatestChatMessage; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.dnd.gongmuin.question_post.domain.QuestionPost; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -29,10 +29,10 @@ public static ChatRoom toChatRoom( public static ChatRoomDetailResponse toChatRoomDetailResponse( ChatRoom chatRoom, - Member chatPartner + Member chatPartner, + boolean isInquirer ) { QuestionPost questionPost = chatRoom.getQuestionPost(); - boolean isInquirer = !chatPartner.equals(chatRoom.getInquirer()); return new ChatRoomDetailResponse( questionPost.getId(), questionPost.getJobGroup().getLabel(), diff --git a/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomDetailResponse.java b/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomDetailResponse.java index 86b3fb3e..6c90366e 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomDetailResponse.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomDetailResponse.java @@ -1,6 +1,6 @@ package com.dnd.gongmuin.chatroom.dto.response; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; +import com.dnd.gongmuin.member.dto.response.MemberInfo; public record ChatRoomDetailResponse( Long questionPostId, diff --git a/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomSimpleResponse.java b/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomSimpleResponse.java index aa7fa435..b4737ff8 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomSimpleResponse.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/dto/response/ChatRoomSimpleResponse.java @@ -1,6 +1,6 @@ package com.dnd.gongmuin.chatroom.dto.response; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; +import com.dnd.gongmuin.member.dto.response.MemberInfo; public record ChatRoomSimpleResponse( Long chatRoomId, diff --git a/src/main/java/com/dnd/gongmuin/chatroom/exception/ChatErrorCode.java b/src/main/java/com/dnd/gongmuin/chatroom/exception/ChatErrorCode.java index c3b182b8..24429e5a 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/exception/ChatErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/exception/ChatErrorCode.java @@ -10,8 +10,7 @@ public enum ChatErrorCode implements ErrorCode { INVALID_MESSAGE_TYPE("메시지 타입을 올바르게 입력해주세요.", "CH_001"), - NOT_FOUND_CHAT_ROOM("해당 아이디의 채팅방이 존재하지 않습니다.", "CH_002"), - UNAUTHORIZED_CHAT_ROOM("채팅방 조회 권한이 없습니다.", "CH_003"); + NOT_FOUND_CHAT_ROOM("해당 아이디의 채팅방이 존재하지 않습니다.", "CH_002"); private final String message; private final String code; diff --git a/src/main/java/com/dnd/gongmuin/chatroom/service/ChatRoomService.java b/src/main/java/com/dnd/gongmuin/chatroom/service/ChatRoomService.java index 69d9d916..d0b7b0dd 100644 --- a/src/main/java/com/dnd/gongmuin/chatroom/service/ChatRoomService.java +++ b/src/main/java/com/dnd/gongmuin/chatroom/service/ChatRoomService.java @@ -25,7 +25,6 @@ import com.dnd.gongmuin.common.dto.PageMapper; import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.common.exception.runtime.NotFoundException; -import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.member.domain.Member; import lombok.RequiredArgsConstructor; @@ -73,8 +72,12 @@ public PageResponse getChatRoomsByMember(Member member, @Transactional(readOnly = true) public ChatRoomDetailResponse getChatRoomById(Long chatRoomId, Member member) { ChatRoom chatRoom = getChatRoomById(chatRoomId); - Member chatPartner = getChatPartner(member, chatRoom); - return ChatRoomMapper.toChatRoomDetailResponse(chatRoom, chatPartner); + + return ChatRoomMapper.toChatRoomDetailResponse( + chatRoom, + chatRoom.getChatPartner(member), + chatRoom.isInquirer(member) + ); } private List getChatRoomSimpleResponses(List latestChatMessages, @@ -101,14 +104,4 @@ private ChatRoom getChatRoomById(Long id) { return chatRoomRepository.findById(id) .orElseThrow(() -> new NotFoundException(ChatErrorCode.NOT_FOUND_CHAT_ROOM)); } - - private Member getChatPartner(Member member, ChatRoom chatRoom) { - if (member.equals(chatRoom.getAnswerer())) { - return chatRoom.getInquirer(); - } - if (member.equals(chatRoom.getInquirer())) { - return chatRoom.getAnswerer(); - } - throw new ValidationException(ChatErrorCode.UNAUTHORIZED_CHAT_ROOM); - } } diff --git a/src/main/java/com/dnd/gongmuin/question_post/dto/response/MemberInfo.java b/src/main/java/com/dnd/gongmuin/member/dto/response/MemberInfo.java similarity index 67% rename from src/main/java/com/dnd/gongmuin/question_post/dto/response/MemberInfo.java rename to src/main/java/com/dnd/gongmuin/member/dto/response/MemberInfo.java index f16a0c4f..0556c88b 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/dto/response/MemberInfo.java +++ b/src/main/java/com/dnd/gongmuin/member/dto/response/MemberInfo.java @@ -1,4 +1,4 @@ -package com.dnd.gongmuin.question_post.dto.response; +package com.dnd.gongmuin.member.dto.response; public record MemberInfo( Long memberId, diff --git a/src/main/java/com/dnd/gongmuin/question_post/dto/QuestionPostMapper.java b/src/main/java/com/dnd/gongmuin/question_post/dto/QuestionPostMapper.java index 6375bd9e..698eb808 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/dto/QuestionPostMapper.java +++ b/src/main/java/com/dnd/gongmuin/question_post/dto/QuestionPostMapper.java @@ -6,10 +6,10 @@ import com.dnd.gongmuin.member.domain.JobGroup; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.domain.QuestionPostImage; import com.dnd.gongmuin.question_post.dto.request.RegisterQuestionPostRequest; -import com.dnd.gongmuin.question_post.dto.response.MemberInfo; import com.dnd.gongmuin.question_post.dto.response.QuestionPostDetailResponse; import com.dnd.gongmuin.question_post.dto.response.RegisterQuestionPostResponse; import com.dnd.gongmuin.question_post.dto.response.UpdateQuestionPostResponse; diff --git a/src/main/java/com/dnd/gongmuin/question_post/dto/response/QuestionPostDetailResponse.java b/src/main/java/com/dnd/gongmuin/question_post/dto/response/QuestionPostDetailResponse.java index 935cb504..de942c56 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/dto/response/QuestionPostDetailResponse.java +++ b/src/main/java/com/dnd/gongmuin/question_post/dto/response/QuestionPostDetailResponse.java @@ -2,6 +2,8 @@ import java.util.List; +import com.dnd.gongmuin.member.dto.response.MemberInfo; + public record QuestionPostDetailResponse( Long questionPostId, String title, diff --git a/src/main/java/com/dnd/gongmuin/question_post/dto/response/RegisterQuestionPostResponse.java b/src/main/java/com/dnd/gongmuin/question_post/dto/response/RegisterQuestionPostResponse.java index fc1633c5..649285fc 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/dto/response/RegisterQuestionPostResponse.java +++ b/src/main/java/com/dnd/gongmuin/question_post/dto/response/RegisterQuestionPostResponse.java @@ -2,6 +2,8 @@ import java.util.List; +import com.dnd.gongmuin.member.dto.response.MemberInfo; + public record RegisterQuestionPostResponse( Long questionPostId, String title, 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 67a03769..c00e2eaa 100644 --- a/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/chat/service/ChatRoomServiceTest.java @@ -24,12 +24,10 @@ import com.dnd.gongmuin.chatroom.dto.response.ChatRoomInfo; import com.dnd.gongmuin.chatroom.dto.response.ChatRoomSimpleResponse; import com.dnd.gongmuin.chatroom.dto.response.LatestChatMessage; -import com.dnd.gongmuin.chatroom.exception.ChatErrorCode; import com.dnd.gongmuin.chatroom.repository.ChatMessageQueryRepository; import com.dnd.gongmuin.chatroom.repository.ChatMessageRepository; import com.dnd.gongmuin.chatroom.repository.ChatRoomRepository; import com.dnd.gongmuin.chatroom.service.ChatRoomService; -import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.common.fixture.ChatMessageFixture; import com.dnd.gongmuin.common.fixture.ChatRoomFixture; import com.dnd.gongmuin.common.fixture.MemberFixture; @@ -158,24 +156,4 @@ void getChatRoomById_Answerer() { .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()); - } } \ No newline at end of file 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 992bffe2..4b3e0c88 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 @@ -57,6 +57,7 @@ void teardown() { creditHistoryRepository.deleteAll(); memberRepository.deleteAll(); questionPostRepository.deleteAll(); + chatInquiryRepository.deleteAll(); chatRoomRepository.deleteAll(); chatMessageRepository.deleteAll(); } @@ -82,6 +83,32 @@ void createChatInquiry() throws Exception { .andDo(MockMvcResultHandlers.print()); } + @DisplayName("[채팅 요청 아이디로 상세 채팅 요청을 조회할 수 있다.]") + @Test + void getChatInquiryById() throws Exception { + //given + Member chatPartner = memberRepository.save(MemberFixture.member5()); + QuestionPost questionPost = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); + ChatInquiry chatInquiry = chatInquiryRepository.save( + ChatInquiryFixture.chatInquiry(questionPost, loginMember, chatPartner, INQUIRY_MESSAGE) + ); + + //when & then + mockMvc.perform(get("/api/chat/inquiries/{chatInquiryId}", chatInquiry.getId()) + .cookie(accessToken)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.chatInquiryId") + .value(chatInquiry.getId())) + .andExpect(jsonPath("$.inquiryStatus") + .value(InquiryStatus.PENDING.getLabel())) + .andExpect(jsonPath("$.chatPartner.memberId") + .value(chatPartner.getId())) + .andExpect(jsonPath("$.isInquirer") + .value(chatInquiry.getInquirer().equals(loginMember))) + .andExpect(jsonPath("$.inquiryStatus") + .value(InquiryStatus.PENDING.getLabel())); + } + @DisplayName("[회원의 채팅 요청 목록을 조회할 수 있다.]") @Test void getChatInquiresByMember() throws Exception { 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 7ec73484..e522871f 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 @@ -21,6 +21,7 @@ import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; import com.dnd.gongmuin.chat_inquiry.dto.AcceptChatResponse; +import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryDetailResponse; import com.dnd.gongmuin.chat_inquiry.dto.ChatInquiryResponse; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryRequest; import com.dnd.gongmuin.chat_inquiry.dto.CreateChatInquiryResponse; @@ -134,6 +135,23 @@ void createInquiry_fails() { .hasMessageContaining(MemberErrorCode.NOT_ENOUGH_CREDIT.getMessage()); } + @DisplayName("[채팅 요청 아이디로 채팅 요청 상세를 조회할 수 있다.]") + @Test + void getChatInquiryById() { + //given + Member inquirer = MemberFixture.member(1L); + Member answerer = MemberFixture.member(2L); + given(chatInquiryRepository.findById(1L)) + .willReturn(Optional.of(ChatInquiryFixture.chatInquiry( + 1L, QuestionPostFixture.questionPost(inquirer), inquirer, answerer, INQUIRY_MESSAGE) + )); + //when + ChatInquiryDetailResponse response = chatInquiryService.getChatInquiryById(1L, inquirer); + + //then + assertThat(response.chatPartner().memberId()).isEqualTo(answerer.getId()); + } + @DisplayName("[회원이 속한 채팅 요청 목록을 조회할 수 있다.]") @Test void getChatInquiresByMember() { @@ -238,8 +256,7 @@ void rejectChat() { RejectChatResponse response = chatInquiryService.rejectChat(chatInquiryId, answerer); //then - assertThat(response.inquiryStatus()) - .isEqualTo(InquiryStatus.REJECTED.getLabel()); + assertThat(response.inquiryStatus()).isEqualTo(InquiryStatus.REJECTED.getLabel()); } @DisplayName("[답변자가 채팅 요청을 거절할 때 채팅 거절 알림이 발행된다.]") From 946371178ef731846031059b253d6509825a7a72 Mon Sep 17 00:00:00 2001 From: dudxo Date: Sat, 23 Nov 2024 17:26:43 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[test]=20:=20V1,=20V2=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/service/AnswerServiceTest.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java index 23e8f52e..bdc90b21 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -130,9 +130,9 @@ void chooseAnswer() { QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerRepository.findById(answer.getId())) + given(answerSimpleQueryRepository.findAnswerById(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostRepository.findById(questionPost.getId())) + given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when @@ -152,9 +152,9 @@ void chooseAnswer_fail() { ReflectionTestUtils.setField(questionPost, "reward", member.getCredit() + 1); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerRepository.findById(answer.getId())) + given(answerSimpleQueryRepository.findAnswerById(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostRepository.findById(questionPost.getId())) + given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when & then @@ -174,9 +174,9 @@ void chooseAnswer_fail2() { QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, questioner); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerRepository.findById(answer.getId())) + given(answerSimpleQueryRepository.findAnswerById(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostRepository.findById(questionPost.getId())) + given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when & then @@ -210,8 +210,9 @@ void creditHistoryWithOneHundred() throws Exception { questionPosts.add(questionPost); answers.add(answer1); - given(answerRepository.findById(i)).willReturn(Optional.of(answer1)); - given(questionPostRepository.findById(questionPost.getId())).willReturn(Optional.of(questionPost)); + given(answerSimpleQueryRepository.findAnswerById(i)).willReturn(Optional.of(answer1)); + given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); } // when From 49f801e323b8f9fe356c87a045cf9b658bd5cf67 Mon Sep 17 00:00:00 2001 From: dudxo Date: Sat, 23 Nov 2024 17:33:36 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[feat]=20:=20QuestionPost=20=EB=8B=A8?= =?UTF-8?q?=EA=B1=B4=EC=A1=B0=ED=9A=8C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dnd/gongmuin/answer/service/AnswerService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java index cc15591c..4774da6d 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -51,7 +51,7 @@ public AnswerDetailResponse registerAnswer( RegisterAnswerRequest request, Member member ) { - QuestionPost questionPost = findQuestionPostById(questionPostId); + QuestionPost questionPost = getQuestionPostById(questionPostId); Answer answer = AnswerMapper.toAnswer(questionPostId, questionPost.isQuestioner(member.getId()), request, member); Answer savedAnswer = answerRepository.save(answer); @@ -108,6 +108,11 @@ private Answer getAnswerById(Long answerId) { .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); } + private QuestionPost getQuestionPostById(Long questionPostId) { + return questionPostRepository.findById(questionPostId) + .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); + } + private QuestionPost findQuestionPostById(Long questionPostId) { return questionPostSimpleQueryRepository.findQuestionPostById(questionPostId) .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); From ba52924c64bef301a2a8c38dceb0cc801e925c82 Mon Sep 17 00:00:00 2001 From: hs12 Date: Sat, 23 Nov 2024 18:34:38 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[test]:=20=EC=A0=95=ED=95=A9=EC=84=B1=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20disabled=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/service/AnswerServiceTest.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java index bdc90b21..d8395ce8 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -12,6 +12,7 @@ import java.util.concurrent.Executors; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -28,7 +29,6 @@ import com.dnd.gongmuin.answer.dto.AnswerDetailResponse; import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; import com.dnd.gongmuin.answer.repository.AnswerRepository; -import com.dnd.gongmuin.answer.repository.AnswerSimpleQueryRepository; import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.common.fixture.AnswerFixture; @@ -41,7 +41,6 @@ import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; -import com.dnd.gongmuin.question_post.repository.QuestionPostSimpleQueryRepository; @DisplayName("[AnswerService 테스트]") @ExtendWith(MockitoExtension.class) @@ -52,15 +51,9 @@ class AnswerServiceTest { @Mock private QuestionPostRepository questionPostRepository; - @Mock - private QuestionPostSimpleQueryRepository questionPostSimpleQueryRepository; - @Mock private AnswerRepository answerRepository; - @Mock - private AnswerSimpleQueryRepository answerSimpleQueryRepository; - @Mock private CreditHistoryService creditHistoryService; @@ -130,9 +123,9 @@ void chooseAnswer() { QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerSimpleQueryRepository.findAnswerById(answer.getId())) + given(answerRepository.findByIdWithMember(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + given(questionPostRepository.findByIdWithMember(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when @@ -152,9 +145,9 @@ void chooseAnswer_fail() { ReflectionTestUtils.setField(questionPost, "reward", member.getCredit() + 1); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerSimpleQueryRepository.findAnswerById(answer.getId())) + given(answerRepository.findByIdWithMember(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + given(questionPostRepository.findByIdWithMember(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when & then @@ -174,9 +167,9 @@ void chooseAnswer_fail2() { QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, questioner); Answer answer = AnswerFixture.answer(1L, questionPostId); - given(answerSimpleQueryRepository.findAnswerById(answer.getId())) + given(answerRepository.findByIdWithMember(answer.getId())) .willReturn(Optional.of(answer)); - given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + given(questionPostRepository.findByIdWithMember(questionPost.getId())) .willReturn(Optional.of(questionPost)); //when & then @@ -185,6 +178,7 @@ void chooseAnswer_fail2() { .hasMessageContaining(QuestionPostErrorCode.NOT_AUTHORIZED.getMessage()); } + @Disabled @DisplayName("[동시에 10_000개의 채택이 일어나 크레딧을 입금 받는다.]") @Test void creditHistoryWithOneHundred() throws Exception { @@ -210,8 +204,8 @@ void creditHistoryWithOneHundred() throws Exception { questionPosts.add(questionPost); answers.add(answer1); - given(answerSimpleQueryRepository.findAnswerById(i)).willReturn(Optional.of(answer1)); - given(questionPostSimpleQueryRepository.findQuestionPostById(questionPost.getId())) + given(answerRepository.findByIdWithMember(i)).willReturn(Optional.of(answer1)); + given(questionPostRepository.findByIdWithMember(questionPost.getId())) .willReturn(Optional.of(questionPost)); } From 8086fe9e5e6478943f1215370c0c8d865c8bcf59 Mon Sep 17 00:00:00 2001 From: hs12 Date: Sat, 23 Nov 2024 18:35:14 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[refactor]:=20fetch=20join=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20repository=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/repository/AnswerRepository.java | 5 +++++ .../gongmuin/answer/service/AnswerService.java | 16 ++++++---------- .../chat_inquiry/dto/ChatInquiryResponse.java | 4 +--- .../repository/QuestionPostRepository.java | 7 ++++++- .../answer/controller/AnswerControllerTest.java | 3 --- 5 files changed, 18 insertions(+), 17 deletions(-) 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 e170f249..7577930c 100644 --- a/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java +++ b/src/main/java/com/dnd/gongmuin/answer/repository/AnswerRepository.java @@ -1,6 +1,7 @@ package com.dnd.gongmuin.answer.repository; import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; @@ -21,4 +22,8 @@ public interface AnswerRepository extends JpaRepository { @Modifying(flushAutomatically = true, clearAutomatically = true) @Query("UPDATE Answer a SET a.member = :member WHERE a.member.id = :memberId") void updateAnswersMember(Long memberId, Member member); + + @Query("select a from Answer a " + + "join fetch a.member where a.id = :answerId") + Optional findByIdWithMember(Long answerId); } \ No newline at end of file diff --git a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java index 4774da6d..027c93c9 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -13,7 +13,6 @@ import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; import com.dnd.gongmuin.answer.exception.AnswerErrorCode; import com.dnd.gongmuin.answer.repository.AnswerRepository; -import com.dnd.gongmuin.answer.repository.AnswerSimpleQueryRepository; import com.dnd.gongmuin.common.dto.PageMapper; import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.common.exception.runtime.NotFoundException; @@ -24,7 +23,6 @@ import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; -import com.dnd.gongmuin.question_post.repository.QuestionPostSimpleQueryRepository; import lombok.RequiredArgsConstructor; @@ -36,8 +34,6 @@ public class AnswerService { private final AnswerRepository answerRepository; private final CreditHistoryService creditHistoryService; private final ApplicationEventPublisher eventPublisher; - private final QuestionPostSimpleQueryRepository questionPostSimpleQueryRepository; - private final AnswerSimpleQueryRepository answerSimpleQueryRepository; private static void validateIfQuestioner(Member member, QuestionPost questionPost) { if (!questionPost.isQuestioner(member.getId())) { @@ -77,8 +73,8 @@ public AnswerDetailResponse chooseAnswer( Long answerId, Member member ) { - Answer answer = getAnswerById(answerId); - QuestionPost questionPost = findQuestionPostById(answer.getQuestionPostId()); + Answer answer = getAnswerWithMember(answerId); + QuestionPost questionPost = getQuestionPostWithMember(answer.getQuestionPostId()); validateIfQuestioner(member, questionPost); chooseAnswer(questionPost, answer); @@ -103,8 +99,8 @@ private void validateIfQuestionPostExists(Long questionPostId) { } } - private Answer getAnswerById(Long answerId) { - return answerSimpleQueryRepository.findAnswerById(answerId) + private Answer getAnswerWithMember(Long answerId) { + return answerRepository.findByIdWithMember(answerId) .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); } @@ -113,8 +109,8 @@ private QuestionPost getQuestionPostById(Long questionPostId) { .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); } - private QuestionPost findQuestionPostById(Long questionPostId) { - return questionPostSimpleQueryRepository.findQuestionPostById(questionPostId) + private QuestionPost getQuestionPostWithMember(Long questionPostId) { + return questionPostRepository.findByIdWithMember(questionPostId) .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); } } \ No newline at end of file diff --git a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java index 384bc5f8..468315c3 100644 --- a/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java +++ b/src/main/java/com/dnd/gongmuin/chat_inquiry/dto/ChatInquiryResponse.java @@ -1,10 +1,8 @@ package com.dnd.gongmuin.chat_inquiry.dto; -import com.dnd.gongmuin.chat_inquiry.domain.InquiryStatus; -import com.dnd.gongmuin.member.domain.JobGroup; -import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.dnd.gongmuin.chat_inquiry.domain.ChatInquiry; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.dto.response.MemberInfo; import com.querydsl.core.annotations.QueryProjection; public record ChatInquiryResponse( diff --git a/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostRepository.java b/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostRepository.java index 39d750fb..5fc33635 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostRepository.java +++ b/src/main/java/com/dnd/gongmuin/question_post/repository/QuestionPostRepository.java @@ -1,6 +1,7 @@ package com.dnd.gongmuin.question_post.repository; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -16,7 +17,11 @@ public interface QuestionPostRepository extends JpaRepository findAllByMember(Member member); + @Query("select q from QuestionPost q " + + "join fetch q.member where q.id = :questionPostId") + Optional findByIdWithMember(Long questionPostId); + @Modifying(flushAutomatically = true, clearAutomatically = true) @Query("UPDATE QuestionPost q SET q.member = :member WHERE q.member.id = :memberId") - public void updateQuestionPostsMember(Long memberId, Member member); + void updateQuestionPostsMember(Long memberId, Member member); } \ No newline at end of file diff --git a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java index 9cccbc84..d8888bb9 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -125,7 +125,6 @@ void chooseAnswer() throws Exception { = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); Member answerer = memberRepository.save(MemberFixture.member2()); Answer answer = answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); - long startTime = System.currentTimeMillis(); mockMvc.perform(post("/api/question-posts/answers/{answerId}", answer.getId()) .cookie(accessToken) @@ -138,7 +137,5 @@ void chooseAnswer() throws Exception { .andExpect(jsonPath("$.memberInfo.nickname").value(answerer.getNickname())) .andExpect(jsonPath("$.memberInfo.memberJobGroup").value(answerer.getJobGroup().getLabel()) ); - long endTime = System.currentTimeMillis(); - System.out.println("Execution time: " + (endTime - startTime) + " ms"); } } \ No newline at end of file