From c8feb2d24f2daf8ea5a5de2b9d8b50f8a6df1ca7 Mon Sep 17 00:00:00 2001 From: le2sky Date: Tue, 21 Jan 2025 21:00:47 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20comment=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/maeilwiki/comment/Comment.java | 9 +++- .../java/maeilwiki/comment/CommentTest.java | 41 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java b/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java index 50df341..e5b10f1 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java @@ -1,7 +1,6 @@ package maeilwiki.comment; import java.time.LocalDateTime; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -55,4 +54,12 @@ private void validateAnswer(String answer) { throw new IllegalArgumentException("답변은 필수 입력값입니다."); } } + + public void remove() { + if (deletedAt != null) { + throw new IllegalStateException("이미 삭제된 답변입니다."); + } + + deletedAt = LocalDateTime.now(); + } } diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java new file mode 100644 index 0000000..7897b82 --- /dev/null +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java @@ -0,0 +1,41 @@ +package maeilwiki.comment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import maeilwiki.member.Member; +import maeilwiki.wiki.Wiki; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class CommentTest { + + @Test + @DisplayName("답변을 삭제할 수 있다.") + void remove() { + Comment comment = createAnswer(); + + comment.remove(); + + assertThat(comment.getDeletedAt()).isNotNull(); + } + + @Test + @DisplayName("이미 삭제된 답변은 다시 삭제될 수 없다.") + void alreadyRemoved() { + Comment comment = createAnswer(); + comment.remove(); + + assertThatThrownBy(comment::remove) + .isInstanceOf(IllegalStateException.class) + .hasMessage("이미 삭제된 답변입니다."); + } + + private Comment createAnswer() { + Member member = Mockito.mock(Member.class); + Wiki wiki = Mockito.mock(Wiki.class); + + return new Comment("answer", false, member, wiki); + } +} From de9fb5ae0d6d4c0cb3debf8f0e26a716c2502690 Mon Sep 17 00:00:00 2001 From: le2sky Date: Thu, 23 Jan 2025 20:57:30 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20comment=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/maeilwiki/comment/CommentApi.java | 13 +++++++++++++ .../main/java/maeilwiki/comment/CommentService.java | 11 +++++++++++ .../java/maeilwiki/comment/CommentServiceTest.java | 11 ++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java index 08d7c08..70a4807 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -20,6 +21,18 @@ public ResponseEntity createComment(@RequestBody CommentRequest request, @ return ResponseEntity.noContent().build(); } + /** + * wikiId는 현재 사용 계획이 없지만, 입력 받는 이유는 다음과 같습니다. + * - 나중에 특정 위키가 아카이브 상태로 전환되는 기능을 구현할 때는 필요할 수 있습니다. + * - comment가 wiki에 속하는 개념이라는 것을 uri로 표현할 수 있습니다. + */ + @DeleteMapping("/wiki/{wikiId}/comment/{id}") + public ResponseEntity deleteComment(@PathVariable Long wikiId, @PathVariable Long id) { + commentService.remove(id); + + return ResponseEntity.noContent().build(); + } + @PostMapping("/wiki/{wikiId}/comment/{id}/like") public ResponseEntity createCommentLike(@PathVariable Long wikiId, @PathVariable Long id) { commentService.toggleLike(id); diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java index bdcfd80..5d92643 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java @@ -29,6 +29,8 @@ public void comment(CommentRequest request, Long wikiId) { String uuid = UUID.randomUUID().toString(); Member temporalMember = new Member(uuid, uuid, "GITHUB"); memberRepository.save(temporalMember); + + // TODO: 지워진 위키인지 확인해야한다. Wiki wiki = wikiRepository.findById(wikiId) .orElseThrow(NoSuchElementException::new); Comment comment = request.toComment(temporalMember, wiki); @@ -36,6 +38,15 @@ public void comment(CommentRequest request, Long wikiId) { commentRepository.save(comment); } + @Transactional + public void remove(Long commentId) { + // TODO: member 소유인지 확인해야한다. + Comment comment = commentRepository.findById(commentId) + .orElseThrow(NoSuchElementException::new); + + comment.remove(); + } + @Transactional public void toggleLike(Long id) { Member member = memberSetting(); diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java index 65b948a..b8cb6eb 100644 --- a/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java @@ -42,10 +42,19 @@ void notfound() { } @Test - @DisplayName("존재하지 않는 답변에 좋아요를 생성할 수 없다.") + @DisplayName("존재하지 않는 답변을 삭제할 수 없다.") void notFoundComment() { Long unknownCommentId = -1L; + assertThatThrownBy(() -> commentService.remove(unknownCommentId)) + .isInstanceOf(NoSuchElementException.class); + } + + @Test + @DisplayName("존재하지 않는 답변에 좋아요를 생성할 수 없다.") + void notFoundCommentForLike() { + Long unknownCommentId = -1L; + assertThatThrownBy(() -> commentService.toggleLike(unknownCommentId)) .isInstanceOf(NoSuchElementException.class); } From 5f57d923830c959242e577f50d38580fd6172d26 Mon Sep 17 00:00:00 2001 From: le2sky Date: Wed, 22 Jan 2025 14:24:45 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EC=9C=84=ED=82=A4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maeilwiki/comment/CommentRepository.java | 4 +- .../src/main/java/maeilwiki/wiki/Wiki.java | 9 ++- .../src/main/java/maeilwiki/wiki/WikiApi.java | 9 +++ .../main/java/maeilwiki/wiki/WikiService.java | 19 ++++++ .../comment/CommentRepositoryTest.java | 60 ++++++++++++++++ .../java/maeilwiki/comment/CommentTest.java | 6 +- .../java/maeilwiki/wiki/WikiServiceTest.java | 68 +++++++++++++++++++ .../test/java/maeilwiki/wiki/WikiTest.java | 39 +++++++++++ 8 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java create mode 100644 maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java create mode 100644 maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentRepository.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentRepository.java index 9ade6e0..83f3f32 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentRepository.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentRepository.java @@ -2,5 +2,7 @@ import org.springframework.data.jpa.repository.JpaRepository; -interface CommentRepository extends JpaRepository { +public interface CommentRepository extends JpaRepository { + + boolean existsByWikiIdAndDeletedAtIsNull(Long wikiId); } diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/Wiki.java b/maeil-wiki/src/main/java/maeilwiki/wiki/Wiki.java index cf5ef16..9c46a73 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/Wiki.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/Wiki.java @@ -1,7 +1,6 @@ package maeilwiki.wiki; import java.time.LocalDateTime; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -70,4 +69,12 @@ private void validateQuestion(String question) { throw new IllegalArgumentException("질문은 %d자 이하여야 합니다.".formatted(MAX_QUESTION_LENGTH)); } } + + public void remove() { + if (deletedAt != null) { + throw new IllegalStateException("이미 삭제된 위키입니다."); + } + + deletedAt = LocalDateTime.now(); + } } diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java index f4c5560..2c46d29 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java @@ -2,6 +2,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -18,4 +20,11 @@ public ResponseEntity createWiki(@RequestBody WikiRequest request) { return ResponseEntity.noContent().build(); } + + @DeleteMapping("/wiki/{id}") + public ResponseEntity deleteWiki(@PathVariable Long id) { + wikiService.remove(id); + + return ResponseEntity.noContent().build(); + } } diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java index 97afdd1..19d215d 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java @@ -1,7 +1,9 @@ package maeilwiki.wiki; +import java.util.NoSuchElementException; import java.util.UUID; import lombok.RequiredArgsConstructor; +import maeilwiki.comment.CommentRepository; import maeilwiki.member.Member; import maeilwiki.member.MemberRepository; import org.springframework.stereotype.Service; @@ -13,6 +15,7 @@ class WikiService { private final WikiRepository wikiRepository; private final MemberRepository memberRepository; + private final CommentRepository commentRepository; @Transactional public void create(WikiRequest request) { @@ -23,4 +26,20 @@ public void create(WikiRequest request) { wikiRepository.save(wiki); } + + @Transactional + public void remove(Long wikiId) { + validateHasComment(wikiId); + Wiki wiki = wikiRepository.findById(wikiId) + .orElseThrow(NoSuchElementException::new); + + wiki.remove(); + } + + private void validateHasComment(Long wikiId) { + boolean hasComment = commentRepository.existsByWikiIdAndDeletedAtIsNull(wikiId); + if (hasComment) { + throw new IllegalStateException("답변이 존재하는 위키는 삭제할 수 없습니다."); + } + } } diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java new file mode 100644 index 0000000..fcd1be3 --- /dev/null +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java @@ -0,0 +1,60 @@ +package maeilwiki.comment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.UUID; +import maeilwiki.member.Member; +import maeilwiki.member.MemberRepository; +import maeilwiki.support.IntegrationTestSupport; +import maeilwiki.wiki.Wiki; +import maeilwiki.wiki.WikiRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class CommentRepositoryTest extends IntegrationTestSupport { + + @Autowired + private WikiRepository wikiRepository; + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private CommentRepository commentRepository; + + @Test + @DisplayName("주어진 위키에 속하는 답변이 존재하는지 조회한다.") + void existsComment() { + Member member = createMember(); + Wiki wiki = createWiki(member); + Wiki noCommentWiki = createWiki(member); + createComment(member, wiki); + Comment comment = createComment(member, noCommentWiki); + comment.remove(); + + assertAll( + () -> assertThat(commentRepository.existsByWikiIdAndDeletedAtIsNull(wiki.getId())).isTrue(), + () -> assertThat(commentRepository.existsByWikiIdAndDeletedAtIsNull(noCommentWiki.getId())).isFalse() + ); + } + + private Member createMember() { + Member member = new Member(UUID.randomUUID().toString(), UUID.randomUUID().toString(), "GITHUB"); + + return memberRepository.save(member); + } + + private Wiki createWiki(Member member) { + Wiki wiki = new Wiki("question", "backend", false, member); + + return wikiRepository.save(wiki); + } + + private Comment createComment(Member member, Wiki wiki) { + Comment comment = new Comment("answer", false, member, wiki); + + return commentRepository.save(comment); + } +} diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java index 7897b82..cf7a585 100644 --- a/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java @@ -14,7 +14,7 @@ class CommentTest { @Test @DisplayName("답변을 삭제할 수 있다.") void remove() { - Comment comment = createAnswer(); + Comment comment = createComment(); comment.remove(); @@ -24,7 +24,7 @@ void remove() { @Test @DisplayName("이미 삭제된 답변은 다시 삭제될 수 없다.") void alreadyRemoved() { - Comment comment = createAnswer(); + Comment comment = createComment(); comment.remove(); assertThatThrownBy(comment::remove) @@ -32,7 +32,7 @@ void alreadyRemoved() { .hasMessage("이미 삭제된 답변입니다."); } - private Comment createAnswer() { + private Comment createComment() { Member member = Mockito.mock(Member.class); Wiki wiki = Mockito.mock(Wiki.class); diff --git a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java new file mode 100644 index 0000000..6e03349 --- /dev/null +++ b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java @@ -0,0 +1,68 @@ +package maeilwiki.wiki; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.NoSuchElementException; +import java.util.UUID; +import maeilwiki.comment.Comment; +import maeilwiki.comment.CommentRepository; +import maeilwiki.member.Member; +import maeilwiki.member.MemberRepository; +import maeilwiki.support.IntegrationTestSupport; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class WikiServiceTest extends IntegrationTestSupport { + + @Autowired + private WikiRepository wikiRepository; + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private CommentRepository commentRepository; + + @Autowired + private WikiService wikiService; + + @Test + @DisplayName("답변이 존재하는 위키는 삭제할 수 없다.") + void cantRemove() { + Member member = createMember(); + Wiki wiki = createWiki(member); + Comment comment = createComment(member, wiki); + + assertThatThrownBy(() -> wikiService.remove(wiki.getId())) + .isInstanceOf(IllegalStateException.class) + .hasMessage("답변이 존재하는 위키는 삭제할 수 없습니다."); + } + + @Test + @DisplayName("존재하지 않는 위키는 삭제할 수 없다.") + void cantRemoveUnknownWiki() { + Long unknownWikiId = -1L; + + assertThatThrownBy(() -> wikiService.remove(unknownWikiId)) + .isInstanceOf(NoSuchElementException.class); + } + + private Member createMember() { + Member member = new Member(UUID.randomUUID().toString(), UUID.randomUUID().toString(), "GITHUB"); + + return memberRepository.save(member); + } + + private Wiki createWiki(Member member) { + Wiki wiki = new Wiki("question", "backend", false, member); + + return wikiRepository.save(wiki); + } + + private Comment createComment(Member member, Wiki wiki) { + Comment comment = new Comment("answer", false, member, wiki); + + return commentRepository.save(comment); + } +} diff --git a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java new file mode 100644 index 0000000..9ae407d --- /dev/null +++ b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java @@ -0,0 +1,39 @@ +package maeilwiki.wiki; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import maeilwiki.member.Member; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class WikiTest { + + @Test + @DisplayName("위키를 삭제할 수 있다.") + void remove() { + Wiki wiki = createWiki(); + + wiki.remove(); + + assertThat(wiki.getDeletedAt()).isNotNull(); + } + + @Test + @DisplayName("이미 삭제된 위키는 다시 삭제될 수 없다.") + void alreadyRemoved() { + Wiki wiki = createWiki(); + wiki.remove(); + + assertThatThrownBy(wiki::remove) + .isInstanceOf(IllegalStateException.class) + .hasMessage("이미 삭제된 위키입니다."); + } + + private Wiki createWiki() { + Member member = Mockito.mock(Member.class); + + return new Wiki("question", "detail", "backend", false, member); + } +} From 6d3a0cac3c3f668dd45c3a3ec8d85291c9ac4b9e Mon Sep 17 00:00:00 2001 From: le2sky Date: Wed, 22 Jan 2025 14:25:02 +0900 Subject: [PATCH 04/10] =?UTF-8?q?chore:=20wiki=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20yml=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maeil-wiki/src/test/resources/application.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 maeil-wiki/src/test/resources/application.yml diff --git a/maeil-wiki/src/test/resources/application.yml b/maeil-wiki/src/test/resources/application.yml new file mode 100644 index 0000000..cb3ad03 --- /dev/null +++ b/maeil-wiki/src/test/resources/application.yml @@ -0,0 +1,14 @@ +spring: + main: + allow-bean-definition-overriding: true + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + auto_quote_keyword: true + format_sql: true + show-sql: true + sql: + init: + mode: never From f7f9b17cfc1f9fd02126f57a7241ec9a36dcb020 Mon Sep 17 00:00:00 2001 From: le2sky Date: Wed, 22 Jan 2025 14:28:17 +0900 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=EC=82=AD=EC=A0=9C=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9C=84=ED=82=A4=EB=A5=BC=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=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 --- maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java | 3 +-- maeil-wiki/src/main/java/maeilwiki/wiki/WikiRepository.java | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java index 5d92643..e58f838 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java @@ -30,8 +30,7 @@ public void comment(CommentRequest request, Long wikiId) { Member temporalMember = new Member(uuid, uuid, "GITHUB"); memberRepository.save(temporalMember); - // TODO: 지워진 위키인지 확인해야한다. - Wiki wiki = wikiRepository.findById(wikiId) + Wiki wiki = wikiRepository.findByIdAndDeletedAtIsNull(wikiId) .orElseThrow(NoSuchElementException::new); Comment comment = request.toComment(temporalMember, wiki); diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiRepository.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiRepository.java index 49871ae..af4f0fd 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiRepository.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiRepository.java @@ -1,6 +1,9 @@ package maeilwiki.wiki; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface WikiRepository extends JpaRepository { + + Optional findByIdAndDeletedAtIsNull(Long id); } From a3624fb7553876d028a5a70480228b76cf64a837 Mon Sep 17 00:00:00 2001 From: le2sky Date: Wed, 22 Jan 2025 14:30:30 +0900 Subject: [PATCH 06/10] =?UTF-8?q?style:=20=EA=B0=9C=ED=96=89=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 --- maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java index e58f838..7ce1b36 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java @@ -29,7 +29,6 @@ public void comment(CommentRequest request, Long wikiId) { String uuid = UUID.randomUUID().toString(); Member temporalMember = new Member(uuid, uuid, "GITHUB"); memberRepository.save(temporalMember); - Wiki wiki = wikiRepository.findByIdAndDeletedAtIsNull(wikiId) .orElseThrow(NoSuchElementException::new); Comment comment = request.toComment(temporalMember, wiki); From 2707ea357c31751d34a800349c70ea9788ea53ea Mon Sep 17 00:00:00 2001 From: le2sky Date: Wed, 22 Jan 2025 14:30:40 +0900 Subject: [PATCH 07/10] =?UTF-8?q?chore:=20todo=20=EC=A3=BC=EC=84=9D=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 --- maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java index 19d215d..7e93e0a 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java @@ -29,6 +29,7 @@ public void create(WikiRequest request) { @Transactional public void remove(Long wikiId) { + // TODO : member 소유인지 확인해야한다. validateHasComment(wikiId); Wiki wiki = wikiRepository.findById(wikiId) .orElseThrow(NoSuchElementException::new); From a91934bbbf6617433a7f64a7b7db2eca97dbe488 Mon Sep 17 00:00:00 2001 From: le2sky Date: Fri, 24 Jan 2025 15:56:15 +0900 Subject: [PATCH 08/10] =?UTF-8?q?refactor:=20comment=EC=97=90=EC=84=9C=20w?= =?UTF-8?q?iki=EB=A5=BC=20=EC=9D=98=EC=A1=B4=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/maeilwiki/comment/Comment.java | 10 ++--- .../java/maeilwiki/comment/CommentApi.java | 42 ------------------- .../maeilwiki/comment/CommentRequest.java | 7 ++-- .../maeilwiki/comment/CommentService.java | 9 +--- .../src/main/java/maeilwiki/wiki/WikiApi.java | 29 +++++++++++++ .../main/java/maeilwiki/wiki/WikiService.java | 11 +++++ .../comment/CommentRepositoryTest.java | 2 +- .../maeilwiki/comment/CommentServiceTest.java | 12 +----- .../java/maeilwiki/comment/CommentTest.java | 8 ++-- .../java/maeilwiki/wiki/WikiServiceTest.java | 13 +++++- 10 files changed, 66 insertions(+), 77 deletions(-) delete mode 100644 maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java b/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java index e5b10f1..ddce60d 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/Comment.java @@ -14,7 +14,6 @@ import lombok.NoArgsConstructor; import maeilsupport.BaseEntity; import maeilwiki.member.Member; -import maeilwiki.wiki.Wiki; @Entity @Getter @@ -37,16 +36,15 @@ public class Comment extends BaseEntity { @JoinColumn(nullable = false) private Member member; - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(nullable = false) - private Wiki wiki; + @Column(nullable = false) + private Long wikiId; - public Comment(String answer, boolean isAnonymous, Member member, Wiki wiki) { + public Comment(String answer, boolean isAnonymous, Member member, Long wikiId) { validateAnswer(answer); this.answer = answer; this.isAnonymous = isAnonymous; this.member = member; - this.wiki = wiki; + this.wikiId = wikiId; } private void validateAnswer(String answer) { diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java deleted file mode 100644 index 70a4807..0000000 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentApi.java +++ /dev/null @@ -1,42 +0,0 @@ -package maeilwiki.comment; - -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -class CommentApi { - - private final CommentService commentService; - - @PostMapping("/wiki/{wikiId}/comment") - public ResponseEntity createComment(@RequestBody CommentRequest request, @PathVariable Long wikiId) { - commentService.comment(request, wikiId); - - return ResponseEntity.noContent().build(); - } - - /** - * wikiId는 현재 사용 계획이 없지만, 입력 받는 이유는 다음과 같습니다. - * - 나중에 특정 위키가 아카이브 상태로 전환되는 기능을 구현할 때는 필요할 수 있습니다. - * - comment가 wiki에 속하는 개념이라는 것을 uri로 표현할 수 있습니다. - */ - @DeleteMapping("/wiki/{wikiId}/comment/{id}") - public ResponseEntity deleteComment(@PathVariable Long wikiId, @PathVariable Long id) { - commentService.remove(id); - - return ResponseEntity.noContent().build(); - } - - @PostMapping("/wiki/{wikiId}/comment/{id}/like") - public ResponseEntity createCommentLike(@PathVariable Long wikiId, @PathVariable Long id) { - commentService.toggleLike(id); - - return ResponseEntity.noContent().build(); - } -} diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentRequest.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentRequest.java index a01f422..7cd6ca6 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentRequest.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentRequest.java @@ -1,11 +1,10 @@ package maeilwiki.comment; import maeilwiki.member.Member; -import maeilwiki.wiki.Wiki; -record CommentRequest(String answer, boolean isAnonymous) { +public record CommentRequest(String answer, boolean isAnonymous) { - public Comment toComment(Member member, Wiki wiki) { - return new Comment(answer, isAnonymous, member, wiki); + public Comment toComment(Member member, Long wikiId) { + return new Comment(answer, isAnonymous, member, wikiId); } } diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java index 7ce1b36..8dc7344 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java @@ -7,17 +7,14 @@ import lombok.RequiredArgsConstructor; import maeilwiki.member.Member; import maeilwiki.member.MemberRepository; -import maeilwiki.wiki.Wiki; -import maeilwiki.wiki.WikiRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronizationManager; @Service @RequiredArgsConstructor -class CommentService { +public class CommentService { - private final WikiRepository wikiRepository; private final CommentRepository commentRepository; private final MemberRepository memberRepository; private final CommentLikeRepository commentLikeRepository; @@ -29,9 +26,7 @@ public void comment(CommentRequest request, Long wikiId) { String uuid = UUID.randomUUID().toString(); Member temporalMember = new Member(uuid, uuid, "GITHUB"); memberRepository.save(temporalMember); - Wiki wiki = wikiRepository.findByIdAndDeletedAtIsNull(wikiId) - .orElseThrow(NoSuchElementException::new); - Comment comment = request.toComment(temporalMember, wiki); + Comment comment = request.toComment(temporalMember, wikiId); commentRepository.save(comment); } diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java index 2c46d29..9047fa6 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiApi.java @@ -1,6 +1,8 @@ package maeilwiki.wiki; import lombok.RequiredArgsConstructor; +import maeilwiki.comment.CommentRequest; +import maeilwiki.comment.CommentService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -13,6 +15,7 @@ class WikiApi { private final WikiService wikiService; + private final CommentService commentService; @PostMapping("/wiki") public ResponseEntity createWiki(@RequestBody WikiRequest request) { @@ -27,4 +30,30 @@ public ResponseEntity deleteWiki(@PathVariable Long id) { return ResponseEntity.noContent().build(); } + + @PostMapping("/wiki/{wikiId}/comment") + public ResponseEntity createComment(@RequestBody CommentRequest request, @PathVariable Long wikiId) { + wikiService.comment(request, wikiId); + + return ResponseEntity.noContent().build(); + } + + /** + * wikiId는 현재 사용 계획이 없지만, 입력 받는 이유는 다음과 같습니다. + * - 나중에 특정 위키가 아카이브 상태로 전환되는 기능을 구현할 때는 필요할 수 있습니다. + * - comment가 wiki에 속하는 개념이라는 것을 uri로 표현할 수 있습니다. + */ + @DeleteMapping("/wiki/{wikiId}/comment/{id}") + public ResponseEntity deleteComment(@PathVariable Long wikiId, @PathVariable Long id) { + commentService.remove(id); + + return ResponseEntity.noContent().build(); + } + + @PostMapping("/wiki/{wikiId}/comment/{id}/like") + public ResponseEntity toggleLike(@PathVariable Long wikiId, @PathVariable Long id) { + commentService.toggleLike(id); + + return ResponseEntity.noContent().build(); + } } diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java index 7e93e0a..3cc32c1 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java @@ -4,6 +4,8 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import maeilwiki.comment.CommentRepository; +import maeilwiki.comment.CommentRequest; +import maeilwiki.comment.CommentService; import maeilwiki.member.Member; import maeilwiki.member.MemberRepository; import org.springframework.stereotype.Service; @@ -16,6 +18,7 @@ class WikiService { private final WikiRepository wikiRepository; private final MemberRepository memberRepository; private final CommentRepository commentRepository; + private final CommentService commentService; @Transactional public void create(WikiRequest request) { @@ -37,6 +40,14 @@ public void remove(Long wikiId) { wiki.remove(); } + @Transactional + public void comment(CommentRequest request, Long wikiId) { + Wiki wiki = wikiRepository.findByIdAndDeletedAtIsNull(wikiId) + .orElseThrow(NoSuchElementException::new); + + commentService.comment(request, wiki.getId()); + } + private void validateHasComment(Long wikiId) { boolean hasComment = commentRepository.existsByWikiIdAndDeletedAtIsNull(wikiId); if (hasComment) { diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java index fcd1be3..1a2816a 100644 --- a/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentRepositoryTest.java @@ -53,7 +53,7 @@ private Wiki createWiki(Member member) { } private Comment createComment(Member member, Wiki wiki) { - Comment comment = new Comment("answer", false, member, wiki); + Comment comment = new Comment("answer", false, member, wiki.getId()); return commentRepository.save(comment); } diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java index b8cb6eb..4504c36 100644 --- a/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentServiceTest.java @@ -31,16 +31,6 @@ class CommentServiceTest extends IntegrationTestSupport { @Autowired private WikiRepository wikiRepository; - @Test - @DisplayName("존재하지 않는 위키에 답변을 작성할 수 없다.") - void notfound() { - CommentRequest request = new CommentRequest("답변을 작성합니다.", false); - Long unknownWikiId = -1L; - - assertThatThrownBy(() -> commentService.comment(request, unknownWikiId)) - .isInstanceOf(NoSuchElementException.class); - } - @Test @DisplayName("존재하지 않는 답변을 삭제할 수 없다.") void notFoundComment() { @@ -89,7 +79,7 @@ private Comment createComment() { Wiki wiki = new Wiki("question", "backend", false, member); wikiRepository.save(wiki); - Comment comment = new Comment("answer", false, member, wiki); + Comment comment = new Comment("answer", false, member, wiki.getId()); return commentRepository.save(comment); } } diff --git a/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java index cf7a585..72a3a3b 100644 --- a/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/comment/CommentTest.java @@ -2,12 +2,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; import maeilwiki.member.Member; -import maeilwiki.wiki.Wiki; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; class CommentTest { @@ -33,9 +32,8 @@ void alreadyRemoved() { } private Comment createComment() { - Member member = Mockito.mock(Member.class); - Wiki wiki = Mockito.mock(Wiki.class); + Member member = mock(Member.class); - return new Comment("answer", false, member, wiki); + return new Comment("answer", false, member, 1L); } } diff --git a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java index 6e03349..d43d79c 100644 --- a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiServiceTest.java @@ -6,6 +6,7 @@ import java.util.UUID; import maeilwiki.comment.Comment; import maeilwiki.comment.CommentRepository; +import maeilwiki.comment.CommentRequest; import maeilwiki.member.Member; import maeilwiki.member.MemberRepository; import maeilwiki.support.IntegrationTestSupport; @@ -27,6 +28,16 @@ class WikiServiceTest extends IntegrationTestSupport { @Autowired private WikiService wikiService; + @Test + @DisplayName("존재하지 않는 위키에 답변을 작성할 수 없다.") + void notfound() { + CommentRequest request = new CommentRequest("답변을 작성합니다.", false); + Long unknownWikiId = -1L; + + assertThatThrownBy(() -> wikiService.comment(request, unknownWikiId)) + .isInstanceOf(NoSuchElementException.class); + } + @Test @DisplayName("답변이 존재하는 위키는 삭제할 수 없다.") void cantRemove() { @@ -61,7 +72,7 @@ private Wiki createWiki(Member member) { } private Comment createComment(Member member, Wiki wiki) { - Comment comment = new Comment("answer", false, member, wiki); + Comment comment = new Comment("answer", false, member, wiki.getId()); return commentRepository.save(comment); } From d3ab2966054dc8b2beafda43580e68974a9d1eb6 Mon Sep 17 00:00:00 2001 From: le2sky Date: Fri, 24 Jan 2025 16:09:42 +0900 Subject: [PATCH 09/10] =?UTF-8?q?style:=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=95=84=EB=93=9C=20=EC=88=9C=EC=84=9C=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 --- .../java/maeilwiki/comment/CommentService.java | 2 +- .../src/main/java/maeilwiki/wiki/WikiService.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java index 8dc7344..1c0ee8e 100644 --- a/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java +++ b/maeil-wiki/src/main/java/maeilwiki/comment/CommentService.java @@ -15,8 +15,8 @@ @RequiredArgsConstructor public class CommentService { - private final CommentRepository commentRepository; private final MemberRepository memberRepository; + private final CommentRepository commentRepository; private final CommentLikeRepository commentLikeRepository; private final Map transactionTmpMemberMap = new ConcurrentHashMap<>(); diff --git a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java index 3cc32c1..73c12c8 100644 --- a/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java +++ b/maeil-wiki/src/main/java/maeilwiki/wiki/WikiService.java @@ -40,6 +40,13 @@ public void remove(Long wikiId) { wiki.remove(); } + private void validateHasComment(Long wikiId) { + boolean hasComment = commentRepository.existsByWikiIdAndDeletedAtIsNull(wikiId); + if (hasComment) { + throw new IllegalStateException("답변이 존재하는 위키는 삭제할 수 없습니다."); + } + } + @Transactional public void comment(CommentRequest request, Long wikiId) { Wiki wiki = wikiRepository.findByIdAndDeletedAtIsNull(wikiId) @@ -47,11 +54,4 @@ public void comment(CommentRequest request, Long wikiId) { commentService.comment(request, wiki.getId()); } - - private void validateHasComment(Long wikiId) { - boolean hasComment = commentRepository.existsByWikiIdAndDeletedAtIsNull(wikiId); - if (hasComment) { - throw new IllegalStateException("답변이 존재하는 위키는 삭제할 수 없습니다."); - } - } } From 737fd85098cd138ea7cf011159a4d0684b89c2f7 Mon Sep 17 00:00:00 2001 From: le2sky Date: Fri, 24 Jan 2025 16:12:24 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor:=20mockito=20static=20import=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java index 9ae407d..482f033 100644 --- a/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java +++ b/maeil-wiki/src/test/java/maeilwiki/wiki/WikiTest.java @@ -2,11 +2,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; import maeilwiki.member.Member; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; class WikiTest { @@ -32,7 +32,7 @@ void alreadyRemoved() { } private Wiki createWiki() { - Member member = Mockito.mock(Member.class); + Member member = mock(Member.class); return new Wiki("question", "detail", "backend", false, member); }