From 0c43f32082779ee48facd142d8100880485ed332 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:11:18 +0900 Subject: [PATCH 01/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EC=A6=9D=EA=B0=90=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dnd/gongmuin/member/domain/Member.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/dnd/gongmuin/member/domain/Member.java b/src/main/java/com/dnd/gongmuin/member/domain/Member.java index 3ae5700d..4976abc2 100644 --- a/src/main/java/com/dnd/gongmuin/member/domain/Member.java +++ b/src/main/java/com/dnd/gongmuin/member/domain/Member.java @@ -5,6 +5,8 @@ import static lombok.AccessLevel.*; import com.dnd.gongmuin.common.entity.TimeBaseEntity; +import com.dnd.gongmuin.common.exception.runtime.ValidationException; +import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -93,4 +95,15 @@ public void updateAdditionalInfo(String nickname, String officialEmail, this.jobCategory = jobCategory; } + public void decreaseCredit(int credit) { + if (this.credit < credit) { + throw new ValidationException(QuestionPostErrorCode.NOT_ENOUGH_CREDIT); + } + this.credit -= credit; + } + + public void increaseCredit(int credit) { + this.credit += credit; + } + } From 37338874a125ae17b969bd3ec661a0dd1b897257 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:12:14 +0900 Subject: [PATCH 02/33] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/exception/AnswerErrorCode.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/answer/exception/AnswerErrorCode.java diff --git a/src/main/java/com/dnd/gongmuin/answer/exception/AnswerErrorCode.java b/src/main/java/com/dnd/gongmuin/answer/exception/AnswerErrorCode.java new file mode 100644 index 00000000..9afff6fd --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/answer/exception/AnswerErrorCode.java @@ -0,0 +1,17 @@ +package com.dnd.gongmuin.answer.exception; + +import com.dnd.gongmuin.common.exception.ErrorCode; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum AnswerErrorCode implements ErrorCode { + + NOT_FOUND_ANSWER("해당 아이디의 답변이 존재하지 않습니다.", "ANS_001"), + ALREADY_CHOSEN_ANSWER_EXISTS("채택한 답변이 존재합니다.", "ANS_02"); + + private final String message; + private final String code; +} From b064d2bc500388ff85e719a72a0fb7058451bda6 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:13:02 +0900 Subject: [PATCH 03/33] =?UTF-8?q?[feat]=20:=20=EC=A7=88=EB=AC=B8=EA=B8=80?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question_post/exception/QuestionPostErrorCode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java b/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java index cfac1d6e..928ab436 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java @@ -10,7 +10,8 @@ public enum QuestionPostErrorCode implements ErrorCode { NOT_FOUND_QUESTION_POST("해당 아이디의 질문 포스트가 존재하지 않습니다.", "QP_001"), - NOT_ENOUGH_CREDIT("보유한 크레딧이 부족합니다.", "QP_002"); + NOT_ENOUGH_CREDIT("보유한 크레딧이 부족합니다.", "QP_002"), + NOT_AUTHORIZED("질문글에서 해당 작업 권한이 없습니다.", "QP_003"); private final String message; private final String code; From 6cc5e2cc87ea0256260b1c5e3fcffdd424dd50c4 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:15:04 +0900 Subject: [PATCH 04/33] =?UTF-8?q?[refactor]=20:=20=EC=A7=88=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=97=94=ED=8B=B0=ED=8B=B0=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dnd/gongmuin/answer/service/AnswerService.java | 4 +--- .../com/dnd/gongmuin/question_post/domain/QuestionPost.java | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) 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 816ae8fa..f2c02a8f 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -34,9 +34,7 @@ public AnswerDetailResponse registerAnswer( ) { QuestionPost questionPost = questionPostRepository.findById(questionPostId) .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); - boolean isQuestioner - = questionPost.getMember().getId().equals(member.getId()); - Answer answer = AnswerMapper.toAnswer(questionPostId, isQuestioner, request, member); + Answer answer = AnswerMapper.toAnswer(questionPostId, questionPost.isQuestioner(member), request, member); return AnswerMapper.toAnswerDetailResponse(answerRepository.save(answer)); } diff --git a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java index 6b6cb60a..e93672e3 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java +++ b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import com.dnd.gongmuin.common.entity.TimeBaseEntity; import com.dnd.gongmuin.member.domain.JobGroup; @@ -77,4 +78,8 @@ private void addImages(List images) { image.addQuestionPost(this); }); } + + public boolean isQuestioner(Member member) { + return Objects.equals(this.member.getId(), member.getId()); + } } \ No newline at end of file From eda20cebe3b2c1917cc93b1209252951fd77934d Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:16:08 +0900 Subject: [PATCH 05/33] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=B3=80=EA=B2=BD=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dnd/gongmuin/answer/domain/Answer.java | 5 +++++ .../gongmuin/question_post/domain/QuestionPost.java | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java b/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java index 7b5775bc..120f8a7d 100644 --- a/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java +++ b/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java @@ -57,4 +57,9 @@ public static Answer of(String content, boolean isQuestioner, Long questionPostI return new Answer(content, isQuestioner, questionPostId, member); } + public void chooseAnswer(int reward) { + this.isChosen = true; + this.member.increaseCredit(reward); + } + } diff --git a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java index e93672e3..ab15f5fd 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java +++ b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java @@ -7,7 +7,10 @@ import java.util.List; import java.util.Objects; +import com.dnd.gongmuin.answer.domain.Answer; +import com.dnd.gongmuin.answer.exception.AnswerErrorCode; import com.dnd.gongmuin.common.entity.TimeBaseEntity; +import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.member.domain.JobGroup; import com.dnd.gongmuin.member.domain.Member; @@ -82,4 +85,12 @@ private void addImages(List images) { public boolean isQuestioner(Member member) { return Objects.equals(this.member.getId(), member.getId()); } + + public void chooseAnswer(Answer answer) { + if (Boolean.TRUE.equals(this.isChosen)) + throw new ValidationException(AnswerErrorCode.ALREADY_CHOSEN_ANSWER_EXISTS); + this.isChosen = true; + this.member.decreaseCredit(reward); + answer.chooseAnswer(reward); + } } \ No newline at end of file From dacabb9c3e9642ab51f39741c699225ffe3272c1 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:18:27 +0900 Subject: [PATCH 06/33] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/service/AnswerService.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) 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 f2c02a8f..5586ffbc 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -8,10 +8,12 @@ import com.dnd.gongmuin.answer.dto.AnswerDetailResponse; import com.dnd.gongmuin.answer.dto.AnswerMapper; 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.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 com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; @@ -32,8 +34,7 @@ public AnswerDetailResponse registerAnswer( RegisterAnswerRequest request, Member member ) { - QuestionPost questionPost = questionPostRepository.findById(questionPostId) - .orElseThrow(() -> new NotFoundException(QuestionPostErrorCode.NOT_FOUND_QUESTION_POST)); + QuestionPost questionPost = findQuestionPostById(questionPostId); Answer answer = AnswerMapper.toAnswer(questionPostId, questionPost.isQuestioner(member), request, member); return AnswerMapper.toAnswerDetailResponse(answerRepository.save(answer)); } @@ -47,6 +48,24 @@ public PageResponse getAnswersByQuestionPostId(Long questi return PageMapper.toPageResponse(answerResponsePage); } + @Transactional + public AnswerDetailResponse chooseAnswer( + Long answerId, + Member member + ) { + Answer answer = findAnswerById(answerId); + QuestionPost questionPost = findQuestionPostById(answer.getQuestionPostId()); + validateIfQuestioner(member, questionPost); + questionPost.chooseAnswer(answer); + return AnswerMapper.toAnswerDetailResponse(answer); + } + + private static void validateIfQuestioner(Member member, QuestionPost questionPost) { + if (!questionPost.isQuestioner(member)) { + throw new ValidationException(QuestionPostErrorCode.NOT_AUTHORIZED); + } + } + private void validateIfQuestionPostExists(Long questionPostId) { boolean isExists = questionPostRepository.existsById(questionPostId); if (!isExists) { @@ -54,4 +73,13 @@ private void validateIfQuestionPostExists(Long questionPostId) { } } -} + private Answer findAnswerById(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)); + } +} \ No newline at end of file From 8d892df928c49eeea6ff781143692f1484eb0463 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:19:00 +0900 Subject: [PATCH 07/33] =?UTF-8?q?[test]=20:=20Member=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EC=9E=88=EB=8A=94=20=EC=A7=88=EB=AC=B8?= =?UTF-8?q?=EA=B8=80=20fixture=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/fixture/QuestionPostFixture.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/java/com/dnd/gongmuin/common/fixture/QuestionPostFixture.java b/src/test/java/com/dnd/gongmuin/common/fixture/QuestionPostFixture.java index 1cb2898b..ef4fd0ca 100644 --- a/src/test/java/com/dnd/gongmuin/common/fixture/QuestionPostFixture.java +++ b/src/test/java/com/dnd/gongmuin/common/fixture/QuestionPostFixture.java @@ -48,4 +48,22 @@ public static QuestionPost questionPost(Long questionPostId) { return questionPost; } + + public static QuestionPost questionPost(Long questionPostId, Member member) { + QuestionPost questionPost = QuestionPost.of( + "제목", + "내용", + 1000, + JobGroup.of("공업"), + List.of( + QuestionPostImage.from("image1.jpg"), + QuestionPostImage.from("image2.jpg") + ), + member + ); + ReflectionTestUtils.setField(questionPost, "id", questionPostId); + ReflectionTestUtils.setField(questionPost, "createdAt", LocalDateTime.now()); + + return questionPost; + } } From 5a72cab6a6aee81283d0bcfd2774114126114e28 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:21:12 +0900 Subject: [PATCH 08/33] =?UTF-8?q?[test]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=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 | 69 +++++++++++++++++++ 1 file changed, 69 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 01f58ccd..cb2ce227 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -1,5 +1,6 @@ package com.dnd.gongmuin.answer.service; +import static org.assertj.core.api.Assertions.*; import static org.mockito.BDDMockito.*; import java.util.List; @@ -15,16 +16,20 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.SliceImpl; +import org.springframework.test.util.ReflectionTestUtils; import com.dnd.gongmuin.answer.domain.Answer; 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.common.dto.PageResponse; +import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.common.fixture.AnswerFixture; import com.dnd.gongmuin.common.fixture.MemberFixture; import com.dnd.gongmuin.common.fixture.QuestionPostFixture; +import com.dnd.gongmuin.member.domain.Member; import com.dnd.gongmuin.question_post.domain.QuestionPost; +import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; @DisplayName("[AnswerService 테스트]") @@ -87,4 +92,68 @@ void getAnswerByQuestionPostId() { Assertions.assertThat(response.hasNext()).isFalse(); Assertions.assertThat(response.content().get(0).answerId()).isEqualTo(answer1.getId()); } + + @DisplayName("[답변을 채택할 수 있다.]") + @Test + void chooseAnswer() { + //given + Long questionPostId = 1L; + Member member = MemberFixture.member(1L); + QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); + Answer answer = AnswerFixture.answer(1L, questionPostId); + + given(answerRepository.findById(answer.getId())) + .willReturn(Optional.of(answer)); + given(questionPostRepository.findById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); + + //when + AnswerDetailResponse response = answerService.chooseAnswer(answer.getId(), member); + + //then + Assertions.assertThat(response.isChosen()).isTrue(); + } + + @DisplayName("[크레딧이 부족하면 답변을 채택할 수 없다.]") + @Test + void chooseAnswer_fail() { + //given + Long questionPostId = 1L; + Member member = MemberFixture.member(1L); + QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, member); + ReflectionTestUtils.setField(questionPost, "reward", member.getCredit() + 1); + Answer answer = AnswerFixture.answer(1L, questionPostId); + + given(answerRepository.findById(answer.getId())) + .willReturn(Optional.of(answer)); + given(questionPostRepository.findById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); + + //when & then + assertThatThrownBy(() -> answerService.chooseAnswer(answer.getId(), member)) + .isInstanceOf(ValidationException.class) + .hasMessageContaining(QuestionPostErrorCode.NOT_ENOUGH_CREDIT.getMessage()); + + } + + @DisplayName("[질문자가 아니면 채택할 수 없다.]") + @Test + void chooseAnswer_fail2() { + //given + Long questionPostId = 1L; + Member questioner = MemberFixture.member(1L); + Member notQuestioner = MemberFixture.member(2L); + QuestionPost questionPost = QuestionPostFixture.questionPost(questionPostId, questioner); + Answer answer = AnswerFixture.answer(1L, questionPostId); + + given(answerRepository.findById(answer.getId())) + .willReturn(Optional.of(answer)); + given(questionPostRepository.findById(questionPost.getId())) + .willReturn(Optional.of(questionPost)); + + //when & then + assertThatThrownBy(() -> answerService.chooseAnswer(answer.getId(), notQuestioner)) + .isInstanceOf(ValidationException.class) + .hasMessageContaining(QuestionPostErrorCode.NOT_AUTHORIZED.getMessage()); + } } \ No newline at end of file From 097add0ee0be6e14613bd8b9d405b8f8c35dffd2 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:22:06 +0900 Subject: [PATCH 09/33] =?UTF-8?q?[test]=20:=20assertAll=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=ED=95=A8=EC=88=98=EB=93=A4=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/answer/service/AnswerServiceTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 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 cb2ce227..7cec7b46 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -1,6 +1,7 @@ package com.dnd.gongmuin.answer.service; import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.BDDMockito.*; import java.util.List; @@ -88,9 +89,11 @@ void getAnswerByQuestionPostId() { questionPostId); //then - Assertions.assertThat(response.content()).hasSize(2); - Assertions.assertThat(response.hasNext()).isFalse(); - Assertions.assertThat(response.content().get(0).answerId()).isEqualTo(answer1.getId()); + assertAll( + () -> assertThat(response.content()).hasSize(2), + () -> assertThat(response.hasNext()).isFalse(), + () -> assertThat(response.content().get(0).answerId()).isEqualTo(answer1.getId()) + ); } @DisplayName("[답변을 채택할 수 있다.]") From e4f213317778dfc53b967417674c024161e8fc32 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:23:01 +0900 Subject: [PATCH 10/33] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=20API=20=ED=95=A8=EC=88=98=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/answer/controller/AnswerController.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 78da7db5..00a633b7 100644 --- a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java +++ b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java @@ -41,4 +41,13 @@ public ResponseEntity> getAnswersByQuestionPo PageResponse response = answerService.getAnswersByQuestionPostId(questionPostId); return ResponseEntity.ok(response); } + + @PostMapping("/answers/{answerId}") + public ResponseEntity getAnswersByQuestionPostId( + @PathVariable Long answerId, + @AuthenticationPrincipal Member member + ) { + AnswerDetailResponse response = answerService.chooseAnswer(answerId, member); + return ResponseEntity.ok(response); + } } From 6261ab3cc0f5e27f86dd2789dae17ce82c8ddcf0 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:23:55 +0900 Subject: [PATCH 11/33] =?UTF-8?q?[test]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=20API=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AnswerControllerTest.java | 21 +++++++++++++++++++ 1 file changed, 21 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 7fd48e8b..b8e6bf5d 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -113,4 +113,25 @@ void getAnswersByQuestionPostId() throws Exception { .andExpect(jsonPath("$.content[1].answerId").value(answers.get(1).getId())) .andExpect(jsonPath("$.content[1].isQuestioner").value(false)); } + + @DisplayName("[질문자는 답변을 채택할 수 있다.]") + @Test + void chooseAnswer() throws Exception { + QuestionPost questionPost + = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); + Member answerer = memberRepository.save(MemberFixture.member2()); + Answer answer = answerRepository.save(AnswerFixture.answer(questionPost.getId(), answerer)); + + mockMvc.perform(post("/api/question-posts/answers/{answerId}", answer.getId()) + .header(AUTHORIZATION, 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()) + ); + } } \ No newline at end of file From 36ae9ea688c98eafa5b2142cce2daae0ae7f19b6 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:26:07 +0900 Subject: [PATCH 12/33] =?UTF-8?q?[chore]=20:=20swagger=20=EB=AA=85?= =?UTF-8?q?=EC=84=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gongmuin/answer/controller/AnswerController.java | 10 ++++++++++ .../controller/QuestionPostController.java | 4 ++-- 2 files changed, 12 insertions(+), 2 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 00a633b7..7c988947 100644 --- a/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java +++ b/src/main/java/com/dnd/gongmuin/answer/controller/AnswerController.java @@ -15,15 +15,21 @@ import com.dnd.gongmuin.common.dto.PageResponse; import com.dnd.gongmuin.member.domain.Member; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +@Tag(name = "답변 API") @RestController @RequiredArgsConstructor @RequestMapping("/api/question-posts") public class AnswerController { private final AnswerService answerService; + @Operation(summary = "답변 등록 API", description = "질문글에 대한 답변을 작성한다.") + @ApiResponse(useReturnTypeSchema = true) @PostMapping("/{questionPostId}/answers") public ResponseEntity registerAnswer( @PathVariable Long questionPostId, @@ -34,6 +40,8 @@ public ResponseEntity registerAnswer( return ResponseEntity.ok(response); } + @Operation(summary = "답변 조회 API", description = "질문글에 속하는 답변을 모두 조회한다.") + @ApiResponse(useReturnTypeSchema = true) @GetMapping("/{questionPostId}/answers") public ResponseEntity> getAnswersByQuestionPostId( @PathVariable Long questionPostId @@ -42,6 +50,8 @@ public ResponseEntity> getAnswersByQuestionPo return ResponseEntity.ok(response); } + @Operation(summary = "답변 채택 API", description = "질문자가 답변을 채택한다.") + @ApiResponse(useReturnTypeSchema = true) @PostMapping("/answers/{answerId}") public ResponseEntity getAnswersByQuestionPostId( @PathVariable Long answerId, diff --git a/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java b/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java index 36c5de44..851c064d 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java +++ b/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java @@ -27,9 +27,9 @@ public class QuestionPostController { private final QuestionPostService questionPostService; - @PostMapping @Operation(summary = "질문글 등록 API", description = "질문글을 등록한다") @ApiResponse(useReturnTypeSchema = true) + @PostMapping public ResponseEntity registerQuestionPost( @RequestBody RegisterQuestionPostRequest request, @AuthenticationPrincipal Member member @@ -38,9 +38,9 @@ public ResponseEntity registerQuestionPost( return ResponseEntity.ok(response); } - @GetMapping("/{questionPostId}") @Operation(summary = "질문글 상세 조회 API", description = "질문글을 아이디로 상세조회한다.") @ApiResponse(useReturnTypeSchema = true) + @GetMapping("/{questionPostId}") public ResponseEntity getQuestionPostById( @PathVariable("questionPostId") Long questionPostId ) { From 63a553e3705bae33877cfa922f1b836fbd2eb809 Mon Sep 17 00:00:00 2001 From: hs12 Date: Wed, 7 Aug 2024 21:26:41 +0900 Subject: [PATCH 13/33] =?UTF-8?q?[style]=20:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8F=AC=EB=A9=A7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/answer/service/AnswerService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 5586ffbc..1fb957e7 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -28,6 +28,12 @@ public class AnswerService { private final QuestionPostRepository questionPostRepository; private final AnswerRepository answerRepository; + private static void validateIfQuestioner(Member member, QuestionPost questionPost) { + if (!questionPost.isQuestioner(member)) { + throw new ValidationException(QuestionPostErrorCode.NOT_AUTHORIZED); + } + } + @Transactional public AnswerDetailResponse registerAnswer( Long questionPostId, @@ -60,12 +66,6 @@ public AnswerDetailResponse chooseAnswer( return AnswerMapper.toAnswerDetailResponse(answer); } - private static void validateIfQuestioner(Member member, QuestionPost questionPost) { - if (!questionPost.isQuestioner(member)) { - throw new ValidationException(QuestionPostErrorCode.NOT_AUTHORIZED); - } - } - private void validateIfQuestionPostExists(Long questionPostId) { boolean isExists = questionPostRepository.existsById(questionPostId); if (!isExists) { From 8d32fa250b6580c2fae37ad1e079c096f1d57bd8 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 13:34:29 +0900 Subject: [PATCH 14/33] =?UTF-8?q?[style]=20:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dnd/gongmuin/answer/service/AnswerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 1fb957e7..760ea977 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -59,7 +59,7 @@ public AnswerDetailResponse chooseAnswer( Long answerId, Member member ) { - Answer answer = findAnswerById(answerId); + Answer answer = getAnswerById(answerId); QuestionPost questionPost = findQuestionPostById(answer.getQuestionPostId()); validateIfQuestioner(member, questionPost); questionPost.chooseAnswer(answer); @@ -73,7 +73,7 @@ private void validateIfQuestionPostExists(Long questionPostId) { } } - private Answer findAnswerById(Long answerId) { + private Answer getAnswerById(Long answerId) { return answerRepository.findById(answerId) .orElseThrow(() -> new NotFoundException(AnswerErrorCode.NOT_FOUND_ANSWER)); } From 92b338a1f740c3c362f907e6729f4a471aabac5b Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:18:14 +0900 Subject: [PATCH 15/33] =?UTF-8?q?[feat]=20:=20=EC=97=94=ED=8B=B0=ED=8B=B0?= =?UTF-8?q?=EB=AA=85=20=EB=B0=8F=20detail=20=ED=83=80=EC=9E=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CreditHistory.java} | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) rename src/main/java/com/dnd/gongmuin/{credit/Credit.java => credit_history/CreditHistory.java} (73%) diff --git a/src/main/java/com/dnd/gongmuin/credit/Credit.java b/src/main/java/com/dnd/gongmuin/credit_history/CreditHistory.java similarity index 73% rename from src/main/java/com/dnd/gongmuin/credit/Credit.java rename to src/main/java/com/dnd/gongmuin/credit_history/CreditHistory.java index 5269a198..7507d326 100644 --- a/src/main/java/com/dnd/gongmuin/credit/Credit.java +++ b/src/main/java/com/dnd/gongmuin/credit_history/CreditHistory.java @@ -1,4 +1,4 @@ -package com.dnd.gongmuin.credit; +package com.dnd.gongmuin.credit_history; import static jakarta.persistence.FetchType.*; @@ -15,27 +15,25 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Credit extends TimeBaseEntity { +public class CreditHistory extends TimeBaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "credit_id", nullable = false) + @Column(name = "credit_history_id", nullable = false) private Long id; @Enumerated(EnumType.STRING) @Column(name = "type", nullable = false) private CreditType type; - @Enumerated(EnumType.STRING) @Column(name = "detail", nullable = false) - private CreditDetail detail; + private String detail; @Column(name = "amount", nullable = false) private int amount; @@ -44,11 +42,14 @@ public class Credit extends TimeBaseEntity { @JoinColumn(name = "member_id", nullable = false) // 정합성 중요 private Member member; - @Builder - public Credit(CreditType type, CreditDetail detail, int amount, Member member) { + private CreditHistory(CreditType type, String detail, int amount, Member member) { this.type = type; this.detail = detail; this.amount = amount; this.member = member; } + + public static CreditHistory of(CreditType type, String detail, int amount, Member member) { + return new CreditHistory(type, detail, amount, member); + } } From c143c530065adac80a21743280b7591c13fe8964 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:18:50 +0900 Subject: [PATCH 16/33] =?UTF-8?q?[feat]=20:=20CreditType=20enum=EC=97=90?= =?UTF-8?q?=20detail=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{credit => credit_history}/CreditType.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) rename src/main/java/com/dnd/gongmuin/{credit => credit_history}/CreditType.java (66%) diff --git a/src/main/java/com/dnd/gongmuin/credit/CreditType.java b/src/main/java/com/dnd/gongmuin/credit_history/CreditType.java similarity index 66% rename from src/main/java/com/dnd/gongmuin/credit/CreditType.java rename to src/main/java/com/dnd/gongmuin/credit_history/CreditType.java index 0d548f4b..fc8fc959 100644 --- a/src/main/java/com/dnd/gongmuin/credit/CreditType.java +++ b/src/main/java/com/dnd/gongmuin/credit_history/CreditType.java @@ -1,4 +1,4 @@ -package com.dnd.gongmuin.credit; +package com.dnd.gongmuin.credit_history; import java.util.Arrays; @@ -9,12 +9,13 @@ @RequiredArgsConstructor public enum CreditType { - CHOOSE("채택하기"), - CHOSEN("채택받기"), - CHAT_REQUEST("채팅신청"), - CHAT_ACCEPT("채팅받기"); + CHOOSE("채택하기", "출금"), + CHOSEN("채택받기", "입금"), + CHAT_REQUEST("채팅신청", "출금"), + CHAT_ACCEPT("채팅받기", "입금"); private final String label; + private final String detail; public static CreditType of(String input) { return Arrays.stream(values()) From a74b8d321dbf2ef868c3fa6962b11132c96f2eb1 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:21:59 +0900 Subject: [PATCH 17/33] =?UTF-8?q?[remove]=20:=20creditDetail=20enum=20?= =?UTF-8?q?=EC=82=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dnd/gongmuin/credit/CreditDetail.java | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/main/java/com/dnd/gongmuin/credit/CreditDetail.java diff --git a/src/main/java/com/dnd/gongmuin/credit/CreditDetail.java b/src/main/java/com/dnd/gongmuin/credit/CreditDetail.java deleted file mode 100644 index a34c24b6..00000000 --- a/src/main/java/com/dnd/gongmuin/credit/CreditDetail.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.dnd.gongmuin.credit; - -import java.util.Arrays; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum CreditDetail { - - DEPOSIT("입금"), - WITHDRAWAL("출금"); - - private final String label; - - public static CreditDetail of(String input) { - return Arrays.stream(values()) - .filter(detail -> detail.isEqual(input)) - .findAny() - .orElseThrow(IllegalArgumentException::new); - } - - private boolean isEqual(String input) { - return input.equals(this.label); - } -} From b426e1c0f8978f79837f3fb3e547969aefb1d5f9 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:22:23 +0900 Subject: [PATCH 18/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=EC=BD=94=EB=93=9C=20member=20=EC=98=81?= =?UTF-8?q?=EC=97=AD=EC=9C=BC=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 --- src/main/java/com/dnd/gongmuin/member/domain/Member.java | 4 ++-- .../com/dnd/gongmuin/member/exception/MemberErrorCode.java | 3 ++- .../question_post/exception/QuestionPostErrorCode.java | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/member/domain/Member.java b/src/main/java/com/dnd/gongmuin/member/domain/Member.java index 4976abc2..2b72bf48 100644 --- a/src/main/java/com/dnd/gongmuin/member/domain/Member.java +++ b/src/main/java/com/dnd/gongmuin/member/domain/Member.java @@ -6,7 +6,7 @@ import com.dnd.gongmuin.common.entity.TimeBaseEntity; import com.dnd.gongmuin.common.exception.runtime.ValidationException; -import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; +import com.dnd.gongmuin.member.exception.MemberErrorCode; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -97,7 +97,7 @@ public void updateAdditionalInfo(String nickname, String officialEmail, public void decreaseCredit(int credit) { if (this.credit < credit) { - throw new ValidationException(QuestionPostErrorCode.NOT_ENOUGH_CREDIT); + throw new ValidationException(MemberErrorCode.NOT_ENOUGH_CREDIT); } this.credit -= credit; } diff --git a/src/main/java/com/dnd/gongmuin/member/exception/MemberErrorCode.java b/src/main/java/com/dnd/gongmuin/member/exception/MemberErrorCode.java index 19ffd702..be9f9919 100644 --- a/src/main/java/com/dnd/gongmuin/member/exception/MemberErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/member/exception/MemberErrorCode.java @@ -10,7 +10,8 @@ public enum MemberErrorCode implements ErrorCode { NOT_FOUND_MEMBER("특정 회원을 찾을 수 없습니다.", "MEMBER_001"), - NOT_FOUND_NEW_MEMBER("신규 회원이 아닙니다.", "MEMBER_002"); + NOT_FOUND_NEW_MEMBER("신규 회원이 아닙니다.", "MEMBER_002"), + NOT_ENOUGH_CREDIT("보유한 크레딧이 부족합니다.", "MEMBER_003"); private final String message; private final String code; diff --git a/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java b/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java index 928ab436..d8b5e61c 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java +++ b/src/main/java/com/dnd/gongmuin/question_post/exception/QuestionPostErrorCode.java @@ -10,8 +10,7 @@ public enum QuestionPostErrorCode implements ErrorCode { NOT_FOUND_QUESTION_POST("해당 아이디의 질문 포스트가 존재하지 않습니다.", "QP_001"), - NOT_ENOUGH_CREDIT("보유한 크레딧이 부족합니다.", "QP_002"), - NOT_AUTHORIZED("질문글에서 해당 작업 권한이 없습니다.", "QP_003"); + NOT_AUTHORIZED("질문글에서 해당 작업 권한이 없습니다.", "QP_002"); private final String message; private final String code; From 8baaed93d91bfdd3d681ed72926d7261b40eeec1 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:26:25 +0900 Subject: [PATCH 19/33] =?UTF-8?q?[feat]=20:=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B1=84=ED=83=9D=20=EC=8B=9C=20=ED=95=84=EB=93=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B1=85=EC=9E=84?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/dnd/gongmuin/answer/domain/Answer.java | 3 +-- .../com/dnd/gongmuin/question_post/domain/QuestionPost.java | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java b/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java index 120f8a7d..940ce7da 100644 --- a/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java +++ b/src/main/java/com/dnd/gongmuin/answer/domain/Answer.java @@ -57,9 +57,8 @@ public static Answer of(String content, boolean isQuestioner, Long questionPostI return new Answer(content, isQuestioner, questionPostId, member); } - public void chooseAnswer(int reward) { + public void updateIsChosen() { this.isChosen = true; - this.member.increaseCredit(reward); } } diff --git a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java index ab15f5fd..0638ee8a 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java +++ b/src/main/java/com/dnd/gongmuin/question_post/domain/QuestionPost.java @@ -86,11 +86,10 @@ public boolean isQuestioner(Member member) { return Objects.equals(this.member.getId(), member.getId()); } - public void chooseAnswer(Answer answer) { + public void updateIsChosen(Answer answer) { if (Boolean.TRUE.equals(this.isChosen)) throw new ValidationException(AnswerErrorCode.ALREADY_CHOSEN_ANSWER_EXISTS); this.isChosen = true; - this.member.decreaseCredit(reward); - answer.chooseAnswer(reward); + answer.updateIsChosen(); } } \ No newline at end of file From d7492ab32ac328d262694f4ac3feaa2aaba6201c Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:27:13 +0900 Subject: [PATCH 20/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EB=82=B4=EC=97=AD=20repository=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/CreditHistoryRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/credit_history/repository/CreditHistoryRepository.java diff --git a/src/main/java/com/dnd/gongmuin/credit_history/repository/CreditHistoryRepository.java b/src/main/java/com/dnd/gongmuin/credit_history/repository/CreditHistoryRepository.java new file mode 100644 index 00000000..cb0f194d --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/credit_history/repository/CreditHistoryRepository.java @@ -0,0 +1,8 @@ +package com.dnd.gongmuin.credit_history.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.dnd.gongmuin.credit_history.CreditHistory; + +public interface CreditHistoryRepository extends JpaRepository { +} From e281619f273dca2fcf7ea006029b5bf8b93b8228 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:27:27 +0900 Subject: [PATCH 21/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EB=82=B4=EC=97=AD=20Mapper=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../credit_history/dto/CreditHistoryMapper.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java diff --git a/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java b/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java new file mode 100644 index 00000000..813f52a3 --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java @@ -0,0 +1,16 @@ +package com.dnd.gongmuin.credit_history.dto; + +import com.dnd.gongmuin.credit_history.CreditHistory; +import com.dnd.gongmuin.credit_history.CreditType; +import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.question_post.domain.QuestionPost; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CreditHistoryMapper { + public static CreditHistory toCredit(CreditType creditType, QuestionPost questionPost, Member member) { + return CreditHistory.of(creditType, creditType.getDetail(), questionPost.getReward(), member); + } +} From 72b739a3b72f3e05bc4dd3dc8a92bffdf919d7d3 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:27:45 +0900 Subject: [PATCH 22/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EB=82=B4=EC=97=AD=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=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 --- .../service/CreditHistoryService.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java diff --git a/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java b/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java new file mode 100644 index 00000000..096c820d --- /dev/null +++ b/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java @@ -0,0 +1,29 @@ +package com.dnd.gongmuin.credit_history.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.gongmuin.answer.domain.Answer; +import com.dnd.gongmuin.credit_history.CreditType; +import com.dnd.gongmuin.credit_history.dto.CreditHistoryMapper; +import com.dnd.gongmuin.credit_history.repository.CreditHistoryRepository; +import com.dnd.gongmuin.question_post.domain.QuestionPost; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class CreditHistoryService { + + private final CreditHistoryRepository creditHistoryRepository; + + @Transactional + public void saveChosenCreditHistory(QuestionPost questionPost, Answer answer) { + creditHistoryRepository.saveAll(List.of( + CreditHistoryMapper.toCredit(CreditType.CHOSEN, questionPost, answer.getMember()), + CreditHistoryMapper.toCredit(CreditType.CHOOSE, questionPost, questionPost.getMember()) + )); + } +} From d1acbd18f82ef2e6505ba4c4d5af44aa0277ce90 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:28:39 +0900 Subject: [PATCH 23/33] =?UTF-8?q?[feat]=20:=20errorCode=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=8F=99=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gongmuin/question_post/service/QuestionPostService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java b/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java index ff341003..a1783dcb 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java +++ b/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java @@ -6,6 +6,7 @@ import com.dnd.gongmuin.common.exception.runtime.NotFoundException; import com.dnd.gongmuin.common.exception.runtime.ValidationException; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.exception.MemberErrorCode; import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.dto.QuestionPostDetailResponse; import com.dnd.gongmuin.question_post.dto.QuestionPostMapper; @@ -25,7 +26,7 @@ public class QuestionPostService { @Transactional public QuestionPostDetailResponse registerQuestionPost(@Valid RegisterQuestionPostRequest request, Member member) { if (member.getCredit() < request.reward()) { - throw new ValidationException(QuestionPostErrorCode.NOT_ENOUGH_CREDIT); + throw new ValidationException(MemberErrorCode.NOT_ENOUGH_CREDIT); } QuestionPost questionPost = QuestionPostMapper.toQuestionPost(request, member); return QuestionPostMapper.toQuestionPostDetailResponse(questionPostRepository.save(questionPost)); From 5b3b5e80fc3d26a9d83f16e7cb34195a40bb2e87 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:32:04 +0900 Subject: [PATCH 24/33] =?UTF-8?q?[feat]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EC=A6=9D=EA=B0=90=20=EB=A1=9C=EC=A7=81=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EB=B0=8F=20=ED=81=AC?= =?UTF-8?q?=EB=A0=88=EB=94=A7=20=EC=A0=80=EC=9E=A5=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/answer/service/AnswerService.java | 12 +++++++++++- 1 file changed, 11 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 760ea977..806de6c8 100644 --- a/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java +++ b/src/main/java/com/dnd/gongmuin/answer/service/AnswerService.java @@ -14,6 +14,7 @@ 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.credit_history.service.CreditHistoryService; import com.dnd.gongmuin.member.domain.Member; import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; @@ -27,6 +28,7 @@ public class AnswerService { private final QuestionPostRepository questionPostRepository; private final AnswerRepository answerRepository; + private final CreditHistoryService creditHistoryService; private static void validateIfQuestioner(Member member, QuestionPost questionPost) { if (!questionPost.isQuestioner(member)) { @@ -62,10 +64,18 @@ public AnswerDetailResponse chooseAnswer( Answer answer = getAnswerById(answerId); QuestionPost questionPost = findQuestionPostById(answer.getQuestionPostId()); validateIfQuestioner(member, questionPost); - questionPost.chooseAnswer(answer); + chooseAnswer(questionPost, answer); + return AnswerMapper.toAnswerDetailResponse(answer); } + private void chooseAnswer(QuestionPost questionPost, Answer answer) { + questionPost.updateIsChosen(answer); + answer.getMember().increaseCredit(questionPost.getReward()); + questionPost.getMember().decreaseCredit(questionPost.getReward()); + creditHistoryService.saveChosenCreditHistory(questionPost, answer); + } + private void validateIfQuestionPostExists(Long questionPostId) { boolean isExists = questionPostRepository.existsById(questionPostId); if (!isExists) { From 2be9fb6be88ea7b09a22539587d7d000bae3443a Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:32:39 +0900 Subject: [PATCH 25/33] =?UTF-8?q?[test]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EB=A1=9C=EC=A7=81=20=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dnd/gongmuin/answer/service/AnswerServiceTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 7cec7b46..a300bec4 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -28,7 +28,9 @@ import com.dnd.gongmuin.common.fixture.AnswerFixture; import com.dnd.gongmuin.common.fixture.MemberFixture; import com.dnd.gongmuin.common.fixture.QuestionPostFixture; +import com.dnd.gongmuin.credit_history.service.CreditHistoryService; import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.member.exception.MemberErrorCode; import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; @@ -45,6 +47,9 @@ class AnswerServiceTest { @Mock private AnswerRepository answerRepository; + @Mock + private CreditHistoryService creditHistoryService; + @InjectMocks private AnswerService answerService; @@ -135,7 +140,7 @@ void chooseAnswer_fail() { //when & then assertThatThrownBy(() -> answerService.chooseAnswer(answer.getId(), member)) .isInstanceOf(ValidationException.class) - .hasMessageContaining(QuestionPostErrorCode.NOT_ENOUGH_CREDIT.getMessage()); + .hasMessageContaining(MemberErrorCode.NOT_ENOUGH_CREDIT.getMessage()); } From 3edb800121cf390a52ec9162d7c8aae8f3955575 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:33:00 +0900 Subject: [PATCH 26/33] =?UTF-8?q?[test]=20:=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question_post/controller/QuestionPostControllerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java b/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java index 328fecc5..577dcbd8 100644 --- a/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java @@ -14,9 +14,9 @@ import com.dnd.gongmuin.common.fixture.QuestionPostFixture; import com.dnd.gongmuin.common.support.ApiTestSupport; +import com.dnd.gongmuin.member.exception.MemberErrorCode; import com.dnd.gongmuin.question_post.domain.QuestionPost; import com.dnd.gongmuin.question_post.dto.RegisterQuestionPostRequest; -import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; @DisplayName("[QuestionPost 통합 테스트]") @@ -77,7 +77,7 @@ void registerQuestionPostFail() throws Exception { ) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.code") - .value(QuestionPostErrorCode.NOT_ENOUGH_CREDIT.getCode())); + .value(MemberErrorCode.NOT_ENOUGH_CREDIT.getCode())); } @DisplayName("[질문글을 조회할 수 있다.]") From ef5ef62711d926ed6ea15a5beb1b973a8fb56f5b Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:33:55 +0900 Subject: [PATCH 27/33] =?UTF-8?q?[test]=20:=20=EC=99=B8=EB=9E=98=ED=82=A4?= =?UTF-8?q?=20=EC=A0=9C=EC=95=BD=20=EC=A1=B0=EA=B1=B4=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20creditRepository=20=EB=A8=BC=EC=A0=80=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/answer/controller/AnswerControllerTest.java | 5 +++++ 1 file changed, 5 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 b8e6bf5d..524d7ac1 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -19,6 +19,7 @@ import com.dnd.gongmuin.common.fixture.MemberFixture; import com.dnd.gongmuin.common.fixture.QuestionPostFixture; import com.dnd.gongmuin.common.support.ApiTestSupport; +import com.dnd.gongmuin.credit_history.repository.CreditHistoryRepository; import com.dnd.gongmuin.member.domain.Member; import com.dnd.gongmuin.member.repository.MemberRepository; import com.dnd.gongmuin.question_post.domain.QuestionPost; @@ -36,8 +37,12 @@ class AnswerControllerTest extends ApiTestSupport { @Autowired private AnswerRepository answerRepository; + @Autowired + private CreditHistoryRepository creditHistoryRepository; + @AfterEach void teardown() { + creditHistoryRepository.deleteAll(); memberRepository.deleteAll(); questionPostRepository.deleteAll(); answerRepository.deleteAll(); From f01fa06720fd12e819e74217d48fed3d18c866fd Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 16:59:47 +0900 Subject: [PATCH 28/33] =?UTF-8?q?[feat]=20:=20=ED=95=84=EC=9A=94=ED=95=9C?= =?UTF-8?q?=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=A7=8C=20=EB=84=98?= =?UTF-8?q?=EA=B8=B0=EB=8F=84=EB=A1=9D=20mapper=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java | 5 ++--- .../credit_history/service/CreditHistoryService.java | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java b/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java index 813f52a3..46e78927 100644 --- a/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java +++ b/src/main/java/com/dnd/gongmuin/credit_history/dto/CreditHistoryMapper.java @@ -3,14 +3,13 @@ import com.dnd.gongmuin.credit_history.CreditHistory; import com.dnd.gongmuin.credit_history.CreditType; import com.dnd.gongmuin.member.domain.Member; -import com.dnd.gongmuin.question_post.domain.QuestionPost; import lombok.AccessLevel; import lombok.NoArgsConstructor; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class CreditHistoryMapper { - public static CreditHistory toCredit(CreditType creditType, QuestionPost questionPost, Member member) { - return CreditHistory.of(creditType, creditType.getDetail(), questionPost.getReward(), member); + public static CreditHistory toCreditHistory(CreditType creditType, int reward, Member member) { + return CreditHistory.of(creditType, creditType.getDetail(), reward, member); } } diff --git a/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java b/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java index 096c820d..e3601ba0 100644 --- a/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java +++ b/src/main/java/com/dnd/gongmuin/credit_history/service/CreditHistoryService.java @@ -22,8 +22,8 @@ public class CreditHistoryService { @Transactional public void saveChosenCreditHistory(QuestionPost questionPost, Answer answer) { creditHistoryRepository.saveAll(List.of( - CreditHistoryMapper.toCredit(CreditType.CHOSEN, questionPost, answer.getMember()), - CreditHistoryMapper.toCredit(CreditType.CHOOSE, questionPost, questionPost.getMember()) + CreditHistoryMapper.toCreditHistory(CreditType.CHOSEN, questionPost.getReward(), answer.getMember()), + CreditHistoryMapper.toCreditHistory(CreditType.CHOOSE, questionPost.getReward(), questionPost.getMember()) )); } } From 15d2cda0bf9660ddd232a147873803270dacd26f Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 17:00:07 +0900 Subject: [PATCH 29/33] =?UTF-8?q?[test]=20:=20=ED=81=AC=EB=A0=88=EB=94=A7?= =?UTF-8?q?=20=EB=82=B4=EC=97=AD=20=EC=A0=80=EC=9E=A5=20=EB=8B=A8=EC=9C=84?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fixture/CreditHistoryFixture.java | 23 ++++++++ .../service/CreditHistoryServiceTest.java | 53 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java create mode 100644 src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java diff --git a/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java b/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java new file mode 100644 index 00000000..3936a39e --- /dev/null +++ b/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java @@ -0,0 +1,23 @@ +package com.dnd.gongmuin.credit_history.fixture; + +import com.dnd.gongmuin.answer.domain.Answer; +import com.dnd.gongmuin.credit_history.CreditHistory; +import com.dnd.gongmuin.credit_history.CreditType; +import com.dnd.gongmuin.member.domain.Member; +import com.dnd.gongmuin.question_post.domain.QuestionPost; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CreditHistoryFixture { + + public static CreditHistory creditHistory(CreditType creditType, int reward, Member member){ + return CreditHistory.of( + creditType, + creditType.getDetail(), + reward, + member + ); + } +} diff --git a/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java b/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java new file mode 100644 index 00000000..078d0e6c --- /dev/null +++ b/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java @@ -0,0 +1,53 @@ +package com.dnd.gongmuin.credit_history.service; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.*; + +import java.util.List; +import java.util.Optional; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.gongmuin.answer.domain.Answer; +import com.dnd.gongmuin.answer.dto.AnswerDetailResponse; +import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; +import com.dnd.gongmuin.common.fixture.AnswerFixture; +import com.dnd.gongmuin.common.fixture.MemberFixture; +import com.dnd.gongmuin.common.fixture.QuestionPostFixture; +import com.dnd.gongmuin.credit_history.CreditHistory; +import com.dnd.gongmuin.credit_history.CreditType; +import com.dnd.gongmuin.credit_history.fixture.CreditHistoryFixture; +import com.dnd.gongmuin.credit_history.repository.CreditHistoryRepository; +import com.dnd.gongmuin.question_post.domain.QuestionPost; + +@DisplayName("[AnswerService 테스트]") +@ExtendWith(MockitoExtension.class) +class CreditHistoryServiceTest { + + @Mock + private CreditHistoryRepository creditHistoryRepository; + + @InjectMocks + private CreditHistoryService creditHistoryService; + + @DisplayName("[크레딧 내역을 저장할 수 있다.]") + @Test + void saveChosenCreditHistory() { + QuestionPost questionPost = QuestionPostFixture.questionPost(MemberFixture.member(1L)); + Answer answer = AnswerFixture.answer(questionPost.getId(), MemberFixture.member(2L)); + + List creditHistories = List.of( + CreditHistoryFixture.creditHistory(CreditType.CHOOSE, questionPost.getReward(), questionPost.getMember()), + CreditHistoryFixture.creditHistory(CreditType.CHOSEN, questionPost.getReward(), answer.getMember()) + ); + given(creditHistoryRepository.saveAll(anyList())).willReturn(creditHistories); + + creditHistoryService.saveChosenCreditHistory(questionPost, answer); + } +} \ No newline at end of file From c968ca37ade62c59fd2fd5284843edff236eaba7 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 17:04:49 +0900 Subject: [PATCH 30/33] =?UTF-8?q?[refactor]=20:=20DTO=20=EB=82=B4=20?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/dnd/gongmuin/answer/dto/RegisterAnswerRequest.java | 5 ----- .../gongmuin/answer/controller/AnswerControllerTest.java | 6 +++--- .../com/dnd/gongmuin/answer/service/AnswerServiceTest.java | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/answer/dto/RegisterAnswerRequest.java b/src/main/java/com/dnd/gongmuin/answer/dto/RegisterAnswerRequest.java index bd452ad6..1a49af16 100644 --- a/src/main/java/com/dnd/gongmuin/answer/dto/RegisterAnswerRequest.java +++ b/src/main/java/com/dnd/gongmuin/answer/dto/RegisterAnswerRequest.java @@ -7,9 +7,4 @@ public record RegisterAnswerRequest( @NotBlank(message = "답변을 입력해주세요.") String content ) { - public static RegisterAnswerRequest from( - String content - ) { - return new RegisterAnswerRequest(content); - } } \ 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 524d7ac1..4409e563 100644 --- a/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/controller/AnswerControllerTest.java @@ -55,7 +55,7 @@ void registerAnswerByOther() throws Exception { Member anotherMember = memberRepository.save(MemberFixture.member2()); QuestionPost questionPost = questionPostRepository.save(QuestionPostFixture.questionPost(anotherMember)); - RegisterAnswerRequest request = RegisterAnswerRequest.from("본문"); + RegisterAnswerRequest request = new RegisterAnswerRequest("본문"); mockMvc.perform(post("/api/question-posts/{questionPostId}/answers", questionPost.getId()) .content(toJson(request)) .contentType(APPLICATION_JSON) @@ -77,7 +77,7 @@ void registerAnswerByQuestioner() throws Exception { QuestionPost questionPost = questionPostRepository.save(QuestionPostFixture.questionPost(loginMember)); - RegisterAnswerRequest request = RegisterAnswerRequest.from("본문"); + RegisterAnswerRequest request = new RegisterAnswerRequest("본문"); mockMvc.perform(post("/api/question-posts/{questionPostId}/answers", questionPost.getId()) .content(toJson(request)) .contentType(APPLICATION_JSON) @@ -105,7 +105,7 @@ void getAnswersByQuestionPostId() throws Exception { answerRepository.save(AnswerFixture.answer(questionPost.getId(), anotherMember)) )); - RegisterAnswerRequest request = RegisterAnswerRequest.from("본문"); + RegisterAnswerRequest request = new RegisterAnswerRequest("본문"); mockMvc.perform(get("/api/question-posts/{questionPostId}/answers", questionPost.getId()) .content(toJson(request)) .contentType(APPLICATION_JSON) 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 a300bec4..17a80223 100644 --- a/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/answer/service/AnswerServiceTest.java @@ -60,7 +60,7 @@ void registerAnswer() { Long questionPostId = 1L; Answer answer = AnswerFixture.answer(1L, questionPostId); RegisterAnswerRequest request = - RegisterAnswerRequest.from("답변 내용"); + new RegisterAnswerRequest("답변 내용"); given(questionPostRepository.findById(questionPostId)) .willReturn(Optional.of(QuestionPostFixture.questionPost(questionPostId))); From 678ce5f719aa4540b926546f598c2df80ae3b049 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 17:07:15 +0900 Subject: [PATCH 31/33] =?UTF-8?q?[fix]=20:=20valid=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=9C=84=EC=B9=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../question_post/controller/QuestionPostController.java | 3 ++- .../gongmuin/question_post/service/QuestionPostService.java | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java b/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java index 851c064d..394c40ee 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java +++ b/src/main/java/com/dnd/gongmuin/question_post/controller/QuestionPostController.java @@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @Tag(name = "질문글 API") @@ -31,7 +32,7 @@ public class QuestionPostController { @ApiResponse(useReturnTypeSchema = true) @PostMapping public ResponseEntity registerQuestionPost( - @RequestBody RegisterQuestionPostRequest request, + @Valid @RequestBody RegisterQuestionPostRequest request, @AuthenticationPrincipal Member member ) { QuestionPostDetailResponse response = questionPostService.registerQuestionPost(request, member); diff --git a/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java b/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java index a1783dcb..7c481d90 100644 --- a/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java +++ b/src/main/java/com/dnd/gongmuin/question_post/service/QuestionPostService.java @@ -14,7 +14,6 @@ import com.dnd.gongmuin.question_post.exception.QuestionPostErrorCode; import com.dnd.gongmuin.question_post.repository.QuestionPostRepository; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @Service @@ -24,7 +23,7 @@ public class QuestionPostService { private final QuestionPostRepository questionPostRepository; @Transactional - public QuestionPostDetailResponse registerQuestionPost(@Valid RegisterQuestionPostRequest request, Member member) { + public QuestionPostDetailResponse registerQuestionPost(RegisterQuestionPostRequest request, Member member) { if (member.getCredit() < request.reward()) { throw new ValidationException(MemberErrorCode.NOT_ENOUGH_CREDIT); } From e3b45b76df762f33b414dec46c718f8533da7915 Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 17:07:46 +0900 Subject: [PATCH 32/33] =?UTF-8?q?[style]=20:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8F=AC=EB=A9=A7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../credit_history/fixture/CreditHistoryFixture.java | 4 +--- .../credit_history/service/CreditHistoryServiceTest.java | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java b/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java index 3936a39e..dbae2307 100644 --- a/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java +++ b/src/test/java/com/dnd/gongmuin/credit_history/fixture/CreditHistoryFixture.java @@ -1,10 +1,8 @@ package com.dnd.gongmuin.credit_history.fixture; -import com.dnd.gongmuin.answer.domain.Answer; import com.dnd.gongmuin.credit_history.CreditHistory; import com.dnd.gongmuin.credit_history.CreditType; import com.dnd.gongmuin.member.domain.Member; -import com.dnd.gongmuin.question_post.domain.QuestionPost; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -12,7 +10,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class CreditHistoryFixture { - public static CreditHistory creditHistory(CreditType creditType, int reward, Member member){ + public static CreditHistory creditHistory(CreditType creditType, int reward, Member member) { return CreditHistory.of( creditType, creditType.getDetail(), diff --git a/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java b/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java index 078d0e6c..af74c85f 100644 --- a/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java +++ b/src/test/java/com/dnd/gongmuin/credit_history/service/CreditHistoryServiceTest.java @@ -1,12 +1,9 @@ package com.dnd.gongmuin.credit_history.service; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.*; import java.util.List; -import java.util.Optional; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -15,8 +12,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import com.dnd.gongmuin.answer.domain.Answer; -import com.dnd.gongmuin.answer.dto.AnswerDetailResponse; -import com.dnd.gongmuin.answer.dto.RegisterAnswerRequest; import com.dnd.gongmuin.common.fixture.AnswerFixture; import com.dnd.gongmuin.common.fixture.MemberFixture; import com.dnd.gongmuin.common.fixture.QuestionPostFixture; From 35a7f7bc280d766da9d05567afa03296d858636d Mon Sep 17 00:00:00 2001 From: hs12 Date: Fri, 9 Aug 2024 17:23:58 +0900 Subject: [PATCH 33/33] =?UTF-8?q?[fix]=20:=20request=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20spring=20bean=20validation=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/QuestionPostControllerTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java b/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java index 577dcbd8..532d56f6 100644 --- a/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java +++ b/src/test/java/com/dnd/gongmuin/question_post/controller/QuestionPostControllerTest.java @@ -36,9 +36,9 @@ void teardown() { void registerQuestionPost() throws Exception { RegisterQuestionPostRequest request = RegisterQuestionPostRequest.of( "제목", - "내용", + "정정기간에 여석이 있을까요?", List.of("image1.jpg", "image2.jpg"), - 1000, + 2000, "공업" ); @@ -62,9 +62,12 @@ void registerQuestionPost() throws Exception { @DisplayName("[보유 크레딧이 부족하면 질문글을 등록할 수 없다.]") @Test void registerQuestionPostFail() throws Exception { + loginMember.decreaseCredit(5000); + memberRepository.save(loginMember); // 크레딧 + RegisterQuestionPostRequest request = RegisterQuestionPostRequest.of( "제목", - "내용", + "정정기간에 여석이 있을까요?", List.of("image1.jpg", "image2.jpg"), loginMember.getCredit() + 1, "공업"