From 31912580a3e9a7e7e8ea13256b7740b5605890fa Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:52:13 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/mapping/PostLike.java | 24 --------- .../solidconnection/post/domain/Post.java | 1 - .../solidconnection/post/domain/PostLike.java | 53 +++++++++++++++++++ .../siteuser/domain/SiteUser.java | 2 +- 4 files changed, 54 insertions(+), 26 deletions(-) delete mode 100644 src/main/java/com/example/solidconnection/entity/mapping/PostLike.java create mode 100644 src/main/java/com/example/solidconnection/post/domain/PostLike.java diff --git a/src/main/java/com/example/solidconnection/entity/mapping/PostLike.java b/src/main/java/com/example/solidconnection/entity/mapping/PostLike.java deleted file mode 100644 index 074806838..000000000 --- a/src/main/java/com/example/solidconnection/entity/mapping/PostLike.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.solidconnection.entity.mapping; - -import com.example.solidconnection.post.domain.Post; -import com.example.solidconnection.siteuser.domain.SiteUser; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@NoArgsConstructor -public class PostLike { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "post_id") - private Post post; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "site_user_id") - private SiteUser siteUser; -} diff --git a/src/main/java/com/example/solidconnection/post/domain/Post.java b/src/main/java/com/example/solidconnection/post/domain/Post.java index 12e43195f..287b255a8 100644 --- a/src/main/java/com/example/solidconnection/post/domain/Post.java +++ b/src/main/java/com/example/solidconnection/post/domain/Post.java @@ -4,7 +4,6 @@ import com.example.solidconnection.comment.domain.Comment; import com.example.solidconnection.entity.PostImage; import com.example.solidconnection.entity.common.BaseEntity; -import com.example.solidconnection.entity.mapping.PostLike; import com.example.solidconnection.post.dto.PostUpdateRequest; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.PostCategory; diff --git a/src/main/java/com/example/solidconnection/post/domain/PostLike.java b/src/main/java/com/example/solidconnection/post/domain/PostLike.java new file mode 100644 index 000000000..0af621370 --- /dev/null +++ b/src/main/java/com/example/solidconnection/post/domain/PostLike.java @@ -0,0 +1,53 @@ +package com.example.solidconnection.post.domain; + +import com.example.solidconnection.siteuser.domain.SiteUser; +import jakarta.persistence.*; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +@EqualsAndHashCode(of = "id") +public class PostLike { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "post_id") + private Post post; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "site_user_id") + private SiteUser siteUser; + + public void setPostAndSiteUser(Post post, SiteUser siteUser) { + + if (this.post != null) { + this.post.getPostLikeList().remove(this); + } + this.post = post; + post.getPostLikeList().add(this); + + if (this.siteUser != null) { + this.siteUser.getPostLikeList().remove(this); + } + this.siteUser = siteUser; + siteUser.getPostLikeList().add(this); + } + + public void resetPostAndSiteUser() { + + if (this.post != null) { + this.post.getPostLikeList().remove(this); + } + this.post = null; + + if (this.siteUser != null) { + this.siteUser.getPostLikeList().remove(this); + } + this.siteUser = null; + } +} diff --git a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java index 300c69492..f3c870ceb 100644 --- a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java +++ b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java @@ -2,7 +2,7 @@ import com.example.solidconnection.comment.domain.Comment; import com.example.solidconnection.post.domain.Post; -import com.example.solidconnection.entity.mapping.PostLike; +import com.example.solidconnection.post.domain.PostLike; import com.example.solidconnection.type.Gender; import com.example.solidconnection.type.PreparationStatus; import com.example.solidconnection.type.Role; From 41feaa30459adbeb6490c2ffd7edd00f39727380 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:52:59 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/repository/PostLikeRepository.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java diff --git a/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java b/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java new file mode 100644 index 000000000..398157c73 --- /dev/null +++ b/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java @@ -0,0 +1,23 @@ +package com.example.solidconnection.post.repository; + +import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.post.domain.Post; +import com.example.solidconnection.siteuser.domain.SiteUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_LIKE; + +@Repository +public interface PostLikeRepository extends JpaRepository { + + Optional findPostLikeByPostAndSiteUser(Post post, SiteUser siteUser); + + default PostLike getByPostAndSiteUser(Post post, SiteUser siteUser) { + return findPostLikeByPostAndSiteUser(post, siteUser) + .orElseThrow(() -> new CustomException(INVALID_POST_LIKE)); + } +} From 716c1f446da6f1797bfc918163d9375203c15e04 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:53:41 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D,=EC=82=AD=EC=A0=9C=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/repository/PostRepository.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/example/solidconnection/post/repository/PostRepository.java b/src/main/java/com/example/solidconnection/post/repository/PostRepository.java index fda9cb166..f5c10875c 100644 --- a/src/main/java/com/example/solidconnection/post/repository/PostRepository.java +++ b/src/main/java/com/example/solidconnection/post/repository/PostRepository.java @@ -4,6 +4,9 @@ import com.example.solidconnection.post.domain.Post; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Optional; @@ -25,4 +28,14 @@ default Post getById(Long id) { return findById(id) .orElseThrow(() -> new CustomException(INVALID_POST_ID)); } + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("UPDATE Post p SET p.likeCount = p.likeCount - 1 " + + "WHERE p.id = :postId AND p.likeCount > 0") + void decreaseLikeCount(@Param("postId") Long postId); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query("UPDATE Post p SET p.likeCount = p.likeCount + 1 " + + "WHERE p.id = :postId") + void increaseLikeCount(@Param("postId") Long postId); } From 1a653a3aabfd69e939e1ab4e33dba300dc4fa74e Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:54:06 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=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 --- .../post/service/PostService.java | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/solidconnection/post/service/PostService.java b/src/main/java/com/example/solidconnection/post/service/PostService.java index d4ed3c081..a847e07fb 100644 --- a/src/main/java/com/example/solidconnection/post/service/PostService.java +++ b/src/main/java/com/example/solidconnection/post/service/PostService.java @@ -8,6 +8,8 @@ import com.example.solidconnection.dto.*; import com.example.solidconnection.board.domain.Board; import com.example.solidconnection.entity.PostImage; +import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.post.repository.PostLikeRepository; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.post.dto.*; import com.example.solidconnection.post.repository.PostRepository; @@ -24,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.EnumUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -41,6 +44,7 @@ public class PostService { private final CommentService commentService; private final RedisService redisService; private final RedisUtils redisUtils; + private final PostLikeRepository postLikeRepository; private String validateCode(String code) { try { @@ -71,8 +75,8 @@ private void validateQuestion(Post post) { } } - private void validatePostCategory(String category){ - if(!EnumUtils.isValidEnum(PostCategory.class, category)){ + private void validatePostCategory(String category) { + if (!EnumUtils.isValidEnum(PostCategory.class, category)) { throw new CustomException(INVALID_POST_CATEGORY); } } @@ -154,7 +158,7 @@ public PostFindResponse findPostById(String email, String code, Long postId) { List commentFindResultDTOList = commentService.findCommentsByPostId(email, postId); // caching && 어뷰징 방지 - if (redisService.isPresent(redisUtils.getValidatePostViewCountRedisKey(email,postId))) { + if (redisService.isPresent(redisUtils.getValidatePostViewCountRedisKey(email, postId))) { redisService.increaseViewCount(redisUtils.getPostViewCountRedisKey(postId)); } @@ -178,4 +182,41 @@ public PostDeleteResponse deletePostById(String email, String code, Long postId) return new PostDeleteResponse(postId); } + + @Transactional(isolation = Isolation.READ_COMMITTED) + public PostLikeResponse likePost(String email, String code, Long postId) { + + String boardCode = validateCode(code); + Post post = postRepository.getById(postId); + SiteUser siteUser = siteUserRepository.getByEmail(email); + validateDuplicatePostLike(post, siteUser); + + PostLike postLike = new PostLike(); + postLike.setPostAndSiteUser(post, siteUser); + postLikeRepository.save(postLike); + postRepository.increaseLikeCount(post.getId()); + + return PostLikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회 + } + + private void validateDuplicatePostLike(Post post, SiteUser siteUser) { + if (postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser).isPresent()) { + throw new CustomException(DUPLICATE_POST_LIKE); + } + } + + @Transactional(isolation = Isolation.READ_COMMITTED) + public PostDislikeResponse dislikePost(String email, String code, Long postId) { + + String boardCode = validateCode(code); + Post post = postRepository.getById(postId); + SiteUser siteUser = siteUserRepository.getByEmail(email); + + PostLike postLike = postLikeRepository.getByPostAndSiteUser(post, siteUser); + postLike.resetPostAndSiteUser(); + postLikeRepository.deleteById(postLike.getId()); + postRepository.decreaseLikeCount(post.getId()); + + return PostDislikeResponse.from(postRepository.getById(postId)); // 실시간성을 위한 재조회 + } } From d102f82bfd79c4a8fca4eff23e3b51bac24a5b45 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:54:40 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=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 --- .../post/controller/PostController.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/com/example/solidconnection/post/controller/PostController.java b/src/main/java/com/example/solidconnection/post/controller/PostController.java index fd452af8a..82ff06af3 100644 --- a/src/main/java/com/example/solidconnection/post/controller/PostController.java +++ b/src/main/java/com/example/solidconnection/post/controller/PostController.java @@ -77,4 +77,26 @@ public ResponseEntity deletePostById( PostDeleteResponse postDeleteResponse = postService.deletePostById(principal.getName(), code, postId); return ResponseEntity.ok().body(postDeleteResponse); } + + @PostMapping(value = "/{code}/posts/{post_id}/like") + public ResponseEntity likePost( + Principal principal, + @PathVariable("code") String code, + @PathVariable("post_id") Long postId + ) { + + PostLikeResponse postLikeResponse = postService.likePost(principal.getName(), code, postId); + return ResponseEntity.ok().body(postLikeResponse); + } + + @DeleteMapping(value = "/{code}/posts/{post_id}/dislike") + public ResponseEntity dislikePost( + Principal principal, + @PathVariable("code") String code, + @PathVariable("post_id") Long postId + ) { + + PostDislikeResponse postDislikeResponse = postService.dislikePost(principal.getName(), code, postId); + return ResponseEntity.ok().body(postDislikeResponse); + } } From 3f28b1a8401b38c1614ec7c7dae7795bb3a93834 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:55:20 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EA=B4=80=EB=A0=A8=20DTO=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/dto/PostDislikeResponse.java | 15 +++++++++++++++ .../post/dto/PostLikeResponse.java | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/post/dto/PostDislikeResponse.java create mode 100644 src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java diff --git a/src/main/java/com/example/solidconnection/post/dto/PostDislikeResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostDislikeResponse.java new file mode 100644 index 000000000..14de9987d --- /dev/null +++ b/src/main/java/com/example/solidconnection/post/dto/PostDislikeResponse.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.post.dto; + +import com.example.solidconnection.post.domain.Post; + +public record PostDislikeResponse( + Long likeCount, + Boolean isLiked +) { + public static PostDislikeResponse from(Post post) { + return new PostDislikeResponse( + post.getLikeCount(), + false + ); + } +} diff --git a/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java new file mode 100644 index 000000000..0ce14b175 --- /dev/null +++ b/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java @@ -0,0 +1,17 @@ +package com.example.solidconnection.post.dto; + +import com.example.solidconnection.post.domain.Post; + +public record PostLikeResponse( + Long likeCount, + Boolean isLiked + + +) { + public static PostLikeResponse from(Post post) { + return new PostLikeResponse( + post.getLikeCount(), + true + ); + } +} From c2ac6b79c7770c42595a34f7bad6f4d69ba6d007 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:55:51 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EA=B4=80=EB=A0=A8=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/solidconnection/custom/exception/ErrorCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java index 0a9df0b61..418d7c8b9 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java @@ -61,6 +61,8 @@ public enum ErrorCode { INVALID_COMMENT_ID(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 댓글입니다."), INVALID_COMMENT_ACCESS(HttpStatus.BAD_REQUEST.value(), "자신의 댓글만 제어할 수 있습니다."), CAN_NOT_UPDATE_DEPRECATED_COMMENT(HttpStatus.BAD_REQUEST.value(),"이미 삭제된 댓글을 수정할 수 없습니다."), + INVALID_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글 좋아요입니다."), + DUPLICATE_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "이미 좋아요한 게시글입니다."), // general JSON_PARSING_FAILED(HttpStatus.BAD_REQUEST.value(), "JSON 파싱을 할 수 없습니다."), From ad7bd6fef02b3b2387bf08c397f386a60de112cc Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:56:29 +0900 Subject: [PATCH 08/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C?= =?UTF-8?q?=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 --- .../unit/repository/PostRepositoryTest.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/example/solidconnection/unit/repository/PostRepositoryTest.java b/src/test/java/com/example/solidconnection/unit/repository/PostRepositoryTest.java index 5fa873d06..ecc2c4f6d 100644 --- a/src/test/java/com/example/solidconnection/unit/repository/PostRepositoryTest.java +++ b/src/test/java/com/example/solidconnection/unit/repository/PostRepositoryTest.java @@ -44,7 +44,7 @@ class PostRepositoryTest { private SiteUser siteUser; @BeforeEach - public void setUp() { + void setUp() { board = createBoard(); boardRepository.save(board); siteUser = createSiteUser(); @@ -92,7 +92,7 @@ private Post createPostWithImages(Board board, SiteUser siteUser) { @Test @Transactional - public void 게시글을_조회할_때_게시글_이미지는_즉시_로딩한다() { + void 게시글을_조회할_때_게시글_이미지는_즉시_로딩한다() { Post foundPost = postRepository.getByIdUsingEntityGraph(post.getId()); foundPost.getPostImageList().size(); // 추가쿼리 발생하지 않는다. @@ -101,7 +101,7 @@ private Post createPostWithImages(Board board, SiteUser siteUser) { @Test @Transactional - public void 게시글을_조회할_때_게시글_이미지는_즉시_로딩한다_유효한_게시글이_아니라면_예외_응답을_반환한다() { + void 게시글을_조회할_때_게시글_이미지는_즉시_로딩한다_유효한_게시글이_아니라면_예외_응답을_반환한다() { // given Long invalidId = -1L; @@ -117,7 +117,7 @@ private Post createPostWithImages(Board board, SiteUser siteUser) { @Test @Transactional - public void 게시글을_조회한다() { + void 게시글을_조회한다() { Post foundPost = postRepository.getById(post.getId()); assertEquals(post, foundPost); @@ -125,7 +125,7 @@ private Post createPostWithImages(Board board, SiteUser siteUser) { @Test @Transactional - public void 게시글을_조회할_때_유효한_게시글이_아니라면_예외_응답을_반환한다() { + void 게시글을_조회할_때_유효한_게시글이_아니라면_예외_응답을_반환한다() { Long invalidId = -1L; CustomException exception = assertThrows(CustomException.class, () -> { @@ -136,4 +136,33 @@ private Post createPostWithImages(Board board, SiteUser siteUser) { assertThat(exception.getCode()) .isEqualTo(INVALID_POST_ID.getCode()); } + + @Test + @Transactional + void 게시글_좋아요를_등록한다() { + // given + Long likeCount = post.getLikeCount(); + + // when + postRepository.increaseLikeCount(post.getId()); + + // then + Post response = postRepository.getById(post.getId()); + assertEquals(response.getLikeCount(), likeCount + 1); + } + + @Test + @Transactional + void 게시글_좋아요를_삭제한다() { + // given + Long likeCount = post.getLikeCount(); + postRepository.increaseLikeCount(post.getId()); + + // when + postRepository.decreaseLikeCount(post.getId()); + + // then + Post response = postRepository.getById(post.getId()); + assertEquals(response.getLikeCount(), likeCount); + } } From 9ba208b51c229352f3e50ad375f81eac5c042a58 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:57:06 +0900 Subject: [PATCH 09/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unit/service/PostServiceTest.java | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java index 7f19707b7..54eb21d93 100644 --- a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java +++ b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java @@ -9,6 +9,8 @@ import com.example.solidconnection.custom.exception.ErrorCode; import com.example.solidconnection.dto.PostFindPostImageResponse; import com.example.solidconnection.entity.PostImage; +import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.post.repository.PostLikeRepository; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.post.dto.*; import com.example.solidconnection.post.repository.PostRepository; @@ -53,6 +55,8 @@ class PostServiceTest { @Mock BoardRepository boardRepository; @Mock + PostLikeRepository postLikeRepository; + @Mock S3Service s3Service; @Mock CommentService commentService; @@ -66,6 +70,7 @@ class PostServiceTest { private Post post; private Post postWithImages; private Post questionPost; + private PostLike postLike; private List imageFiles; private List imageFilesWithMoreThanFiveFiles; private List uploadedFileUrlResponseList; @@ -81,6 +86,7 @@ void setUp() { post = createPost(board, siteUser); postWithImages = createPostWithImages(board, siteUser); questionPost = createQuestionPost(board, siteUser); + postLike = createPostLike(post, siteUser); } private SiteUser createSiteUser() { @@ -147,6 +153,12 @@ private Post createQuestionPost(Board board, SiteUser siteUser) { return post; } + private PostLike createPostLike(Post post, SiteUser siteUser) { + PostLike postLike = new PostLike(); + postLike.setPostAndSiteUser(post, siteUser); + return postLike; + } + private List createMockImageFiles() { List multipartFileList = new ArrayList<>(); multipartFileList.add(new MockMultipartFile("file1", "test1.png", @@ -554,4 +566,125 @@ private List createMockImageFilesWithMoreThanFiveFiles() { assertThat(exception.getCode()) .isEqualTo(ErrorCode.CAN_NOT_DELETE_OR_UPDATE_QUESTION.getCode()); } + + /** + * 게시글 좋아요 + */ + @Test + void 게시글_좋아요를_등록한다() { + // Given + when(postRepository.getById(post.getId())).thenReturn(post); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + + // When + PostLikeResponse postLikeResponse = postService.likePost(siteUser.getEmail(), board.getCode(), post.getId()); + + // Then + assertEquals(postLikeResponse, PostLikeResponse.from(post)); + verify(postLikeRepository, times(1)).save(any(PostLike.class)); + } + + @Test + void 게시글_좋아요를_등록할_때_중복된_좋아요라면_예외_응답을_반환한다() { + when(postRepository.getById(post.getId())).thenReturn(post); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser)).thenReturn(Optional.of(postLike)); + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.likePost(siteUser.getEmail(), board.getCode(), post.getId())); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.DUPLICATE_POST_LIKE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.DUPLICATE_POST_LIKE.getCode()); + } + + @Test + void 게시글_좋아요를_등록할_때_유효한_게시판이_아니라면_예외_응답을_반환한다() { + // Given + String invalidBoardCode = "INVALID_CODE"; + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.likePost(siteUser.getEmail(), invalidBoardCode, post.getId())); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_BOARD_CODE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_BOARD_CODE.getCode()); + } + + @Test + void 게시글_좋아요를_등록할_때_유효한_게시글이_아니라면_예외_응답을_반환한다() { + // Given + Long invalidPostId = -1L; + when(postRepository.getById(invalidPostId)).thenThrow(new CustomException(INVALID_POST_ID)); + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.likePost(siteUser.getEmail(), board.getCode(), invalidPostId)); + assertThat(exception.getMessage()) + .isEqualTo(INVALID_POST_ID.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(INVALID_POST_ID.getCode()); + } + + @Test + void 게시글_좋아요를_삭제한다() { + // Given + Long likeCount = post.getLikeCount(); + when(postRepository.getById(post.getId())).thenReturn(post); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(postLikeRepository.getByPostAndSiteUser(post, siteUser)).thenReturn(postLike); + + // When + PostDislikeResponse postDislikeResponse = postService.dislikePost(siteUser.getEmail(), board.getCode(), post.getId()); + + // Then + assertEquals(postDislikeResponse, PostDislikeResponse.from(post)); + verify(postLikeRepository, times(1)).deleteById(post.getId()); + } + + @Test + void 게시글_좋아요를_삭제할_때_존재하지_않는_좋아요라면_예외_응답을_반환한다() { + when(postRepository.getById(post.getId())).thenReturn(post); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(postLikeRepository.getByPostAndSiteUser(post, siteUser)).thenThrow(new CustomException(INVALID_POST_LIKE)); + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.dislikePost(siteUser.getEmail(), board.getCode(), post.getId())); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_POST_LIKE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_POST_LIKE.getCode()); + } + + @Test + void 게시글_좋아요를_삭제할_때_유효한_게시판이_아니라면_예외_응답을_반환한다() { + // Given + String invalidBoardCode = "INVALID_CODE"; + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.dislikePost(siteUser.getEmail(), invalidBoardCode, post.getId())); + assertThat(exception.getMessage()) + .isEqualTo(ErrorCode.INVALID_BOARD_CODE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(ErrorCode.INVALID_BOARD_CODE.getCode()); + } + + @Test + void 게시글_좋아요를_삭제할_때_유효한_게시글이_아니라면_예외_응답을_반환한다() { + // Given + Long invalidPostId = -1L; + when(postRepository.getById(invalidPostId)).thenThrow(new CustomException(INVALID_POST_ID)); + + // When & Then + CustomException exception = assertThrows(CustomException.class, () -> + postService.dislikePost(siteUser.getEmail(), board.getCode(), invalidPostId)); + assertThat(exception.getMessage()) + .isEqualTo(INVALID_POST_ID.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(INVALID_POST_ID.getCode()); + } } From d9c60e1e12ec3146bc435a8112d3672c8d4d4a17 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:58:11 +0900 Subject: [PATCH 10/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C?= =?UTF-8?q?=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 --- .../repository/PostLikeRepositoryTest.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/test/java/com/example/solidconnection/unit/repository/PostLikeRepositoryTest.java diff --git a/src/test/java/com/example/solidconnection/unit/repository/PostLikeRepositoryTest.java b/src/test/java/com/example/solidconnection/unit/repository/PostLikeRepositoryTest.java new file mode 100644 index 000000000..c39e28497 --- /dev/null +++ b/src/test/java/com/example/solidconnection/unit/repository/PostLikeRepositoryTest.java @@ -0,0 +1,122 @@ +package com.example.solidconnection.unit.repository; + +import com.example.solidconnection.board.domain.Board; +import com.example.solidconnection.board.repository.BoardRepository; +import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.post.repository.PostLikeRepository; +import com.example.solidconnection.post.domain.Post; +import com.example.solidconnection.post.repository.PostRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.PostCategory; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_LIKE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@DataJpaTest +@ActiveProfiles("test") +@DisplayName("게시글 좋아요 레포지토리 테스트") +class PostLikeRepositoryTest { + @Autowired + private PostRepository postRepository; + @Autowired + private BoardRepository boardRepository; + @Autowired + private SiteUserRepository siteUserRepository; + @Autowired + private PostLikeRepository postLikeRepository; + + private Post post; + private Board board; + private SiteUser siteUser; + private PostLike postLike; + + + @BeforeEach + void setUp() { + board = createBoard(); + boardRepository.save(board); + siteUser = createSiteUser(); + siteUserRepository.save(siteUser); + post = createPost(board, siteUser); + post = postRepository.save(post); + postLike = createPostLike(post, siteUser); + postLikeRepository.save(postLike); + } + + private SiteUser createSiteUser() { + return new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + } + + private Board createBoard() { + return new Board( + "FREE", "자유게시판"); + } + + private Post createPost(Board board, SiteUser siteUser) { + Post post = new Post( + "title", + "content", + false, + 0L, + 0L, + PostCategory.valueOf("자유") + ); + post.setBoardAndSiteUser(board, siteUser); + return post; + } + + private PostLike createPostLike(Post post, SiteUser siteUser) { + PostLike postLike = new PostLike(); + postLike.setPostAndSiteUser(post, siteUser); + return postLike; + } + + @Test + @Transactional + void 게시글_좋아요를_조회한다() { + // when + PostLike foundPostLike = postLikeRepository.getByPostAndSiteUser(post, siteUser); + + // then + assertEquals(foundPostLike, postLike); + } + + @Test + @Transactional + void 게시글_좋아요를_조회할_때_유효한_좋아요가_아니라면_예외_응답을_반환한다() { + // given + postLike.resetPostAndSiteUser(); + postLikeRepository.delete(postLike); + + // when, then + CustomException exception = assertThrows(CustomException.class, () -> { + postLikeRepository.getByPostAndSiteUser(post, siteUser); + }); + assertThat(exception.getMessage()) + .isEqualTo(INVALID_POST_LIKE.getMessage()); + assertThat(exception.getCode()) + .isEqualTo(INVALID_POST_LIKE.getCode()); + } +} From 899a5b2ff73f1ec731a3640af88e9fbe1219bf63 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 15:58:57 +0900 Subject: [PATCH 11/15] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EB=8F=99=EC=8B=9C=EC=84=B1=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PostLikeCountConcurrencyTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/test/java/com/example/solidconnection/concurrency/PostLikeCountConcurrencyTest.java diff --git a/src/test/java/com/example/solidconnection/concurrency/PostLikeCountConcurrencyTest.java b/src/test/java/com/example/solidconnection/concurrency/PostLikeCountConcurrencyTest.java new file mode 100644 index 000000000..f07b6821c --- /dev/null +++ b/src/test/java/com/example/solidconnection/concurrency/PostLikeCountConcurrencyTest.java @@ -0,0 +1,141 @@ +package com.example.solidconnection.concurrency; + +import com.example.solidconnection.board.domain.Board; +import com.example.solidconnection.board.repository.BoardRepository; +import com.example.solidconnection.post.domain.Post; +import com.example.solidconnection.post.repository.PostRepository; +import com.example.solidconnection.post.service.PostService; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.PostCategory; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +@ActiveProfiles("test") +@DisplayName("게시글 좋아요 동시성 테스트") +class PostLikeCountConcurrencyTest { + + @Autowired + private PostService postService; + @Autowired + private PostRepository postRepository; + @Autowired + private BoardRepository boardRepository; + @Autowired + private SiteUserRepository siteUserRepository; + + @Value("${view.count.scheduling.delay}") + private int SCHEDULING_DELAY_MS; + private int THREAD_NUMS = 1000; + private int THREAD_POOL_SIZE = 200; + private int TIMEOUT_SECONDS = 10; + + private Post post; + private Board board; + private SiteUser siteUser; + + @BeforeEach + void setUp() { + board = createBoard(); + boardRepository.save(board); + siteUser = createSiteUser(); + siteUserRepository.save(siteUser); + post = createPost(board, siteUser); + postRepository.save(post); + createSiteUsers(); + } + + private SiteUser createSiteUser() { + return new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + } + + private void createSiteUsers() { + for (int i = 0; i < 1000; i++) { + + SiteUser siteUser = new SiteUser( + "email" + i, + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + siteUserRepository.save(siteUser); + } + } + + private Board createBoard() { + return new Board( + "FREE", "자유게시판"); + } + + private Post createPost(Board board, SiteUser siteUser) { + Post post = new Post( + "title", + "content", + false, + 0L, + 0L, + PostCategory.valueOf("자유") + ); + post.setBoardAndSiteUser(board, siteUser); + + return post; + } + + @Test + void 게시글_좋아요_동시성_문제를_해결한다() throws InterruptedException { + + ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + CountDownLatch doneSignal = new CountDownLatch(THREAD_NUMS); + + Long likeCount = postRepository.getById(post.getId()).getLikeCount(); + + for (int i = 0; i < THREAD_NUMS; i++) { + String email = "email" + i; + executorService.submit(() -> { + try { + postService.likePost(email, board.getCode(), post.getId()); + postService.dislikePost(email, board.getCode(), post.getId()); + } finally { + doneSignal.countDown(); + } + }); + } + + doneSignal.await(TIMEOUT_SECONDS, TimeUnit.SECONDS); + executorService.shutdown(); + boolean terminated = executorService.awaitTermination(TIMEOUT_SECONDS, TimeUnit.SECONDS); + if (!terminated) { + System.err.println("ExecutorService did not terminate in the expected time."); + } + + assertEquals(likeCount, postRepository.getById(post.getId()).getLikeCount()); + } + +} From c76be2038ce523447f27a5b31a24d61320f8a8e8 Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 17:32:54 +0900 Subject: [PATCH 12/15] =?UTF-8?q?refactor:=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=A1=B0=ED=9A=8C=EC=8B=9C=20?= =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=97=AC=EB=B6=80=EB=8F=84=20?= =?UTF-8?q?=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/post/dto/PostFindResponse.java | 4 +++- .../solidconnection/post/service/PostService.java | 9 ++++++++- .../solidconnection/unit/service/PostServiceTest.java | 5 +++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java index bbde1ba91..7f5f703af 100644 --- a/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java @@ -19,6 +19,7 @@ public record PostFindResponse( Integer commentCount, String postCategory, Boolean isOwner, + Boolean isLiked, LocalDateTime createdAt, LocalDateTime updatedAt, PostFindBoardResponse postFindBoardResponse, @@ -27,7 +28,7 @@ public record PostFindResponse( List postFindPostImageResponses ) { - public static PostFindResponse from(Post post, Boolean isOwner, PostFindBoardResponse postFindBoardResponse, + public static PostFindResponse from(Post post, Boolean isOwner, Boolean isLiked, PostFindBoardResponse postFindBoardResponse, PostFindSiteUserResponse postFindSiteUserResponse, List postFindCommentResponses, List postFindPostImageResponses @@ -42,6 +43,7 @@ public static PostFindResponse from(Post post, Boolean isOwner, PostFindBoardRes postFindCommentResponses.size(), String.valueOf(post.getCategory()), isOwner, + isLiked, post.getCreatedAt(), post.getUpdatedAt(), postFindBoardResponse, diff --git a/src/main/java/com/example/solidconnection/post/service/PostService.java b/src/main/java/com/example/solidconnection/post/service/PostService.java index a847e07fb..12638a317 100644 --- a/src/main/java/com/example/solidconnection/post/service/PostService.java +++ b/src/main/java/com/example/solidconnection/post/service/PostService.java @@ -85,6 +85,11 @@ private Boolean getIsOwner(Post post, String email) { return post.getSiteUser().getEmail().equals(email); } + private Boolean getIsLiked(Post post, SiteUser siteUser) { + return postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser) + .isPresent(); + } + @Transactional public PostCreateResponse createPost(String email, String code, PostCreateRequest postCreateRequest, List imageFile) { @@ -150,7 +155,9 @@ public PostFindResponse findPostById(String email, String code, Long postId) { String boardCode = validateCode(code); Post post = postRepository.getByIdUsingEntityGraph(postId); + SiteUser siteUser = siteUserRepository.getByEmail(email); Boolean isOwner = getIsOwner(post, email); + Boolean isLiked = getIsLiked(post, siteUser); PostFindBoardResponse boardPostFindResultDTO = PostFindBoardResponse.from(post.getBoard()); PostFindSiteUserResponse siteUserPostFindResultDTO = PostFindSiteUserResponse.from(post.getSiteUser()); @@ -163,7 +170,7 @@ public PostFindResponse findPostById(String email, String code, Long postId) { } return PostFindResponse.from( - post, isOwner, boardPostFindResultDTO, siteUserPostFindResultDTO, commentFindResultDTOList, postImageFindResultDTOList); + post, isOwner, isLiked, boardPostFindResultDTO, siteUserPostFindResultDTO, commentFindResultDTOList, postImageFindResultDTOList); } @Transactional diff --git a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java index 54eb21d93..917d073f5 100644 --- a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java +++ b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java @@ -443,6 +443,8 @@ private List createMockImageFilesWithMoreThanFiveFiles() { // Given List commentFindResultDTOList = new ArrayList<>(); when(postRepository.getByIdUsingEntityGraph(post.getId())).thenReturn(post); + when(siteUserRepository.getByEmail(siteUser.getEmail())).thenReturn(siteUser); + when(postLikeRepository.findPostLikeByPostAndSiteUser(post, siteUser)).thenReturn(Optional.empty()); when(commentService.findCommentsByPostId(siteUser.getEmail(), post.getId())).thenReturn(commentFindResultDTOList); // When @@ -452,6 +454,7 @@ private List createMockImageFilesWithMoreThanFiveFiles() { PostFindResponse expectedResponse = PostFindResponse.from( post, true, + false, PostFindBoardResponse.from(post.getBoard()), PostFindSiteUserResponse.from(post.getSiteUser()), commentFindResultDTOList, @@ -459,6 +462,8 @@ private List createMockImageFilesWithMoreThanFiveFiles() { ); assertEquals(expectedResponse, response); verify(postRepository, times(1)).getByIdUsingEntityGraph(post.getId()); + verify(siteUserRepository, times(1)).getByEmail(siteUser.getEmail()); + verify(postLikeRepository, times(1)).findPostLikeByPostAndSiteUser(post, siteUser); verify(commentService, times(1)).findCommentsByPostId(siteUser.getEmail(), post.getId()); } From 3dcd77258d5cabe433be0ba231e8cb4653cdc44e Mon Sep 17 00:00:00 2001 From: sewon Date: Sat, 17 Aug 2024 17:45:49 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=82=AD=EC=A0=9C=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/solidconnection/post/controller/PostController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/post/controller/PostController.java b/src/main/java/com/example/solidconnection/post/controller/PostController.java index 82ff06af3..c5b974082 100644 --- a/src/main/java/com/example/solidconnection/post/controller/PostController.java +++ b/src/main/java/com/example/solidconnection/post/controller/PostController.java @@ -89,7 +89,7 @@ public ResponseEntity likePost( return ResponseEntity.ok().body(postLikeResponse); } - @DeleteMapping(value = "/{code}/posts/{post_id}/dislike") + @DeleteMapping(value = "/{code}/posts/{post_id}/like") public ResponseEntity dislikePost( Principal principal, @PathVariable("code") String code, From 044cee09cbc54119c34aeca9bcbeba0255d49601 Mon Sep 17 00:00:00 2001 From: sewon Date: Sun, 18 Aug 2024 13:07:15 +0900 Subject: [PATCH 14/15] =?UTF-8?q?refactor:=20CommentCreateRequest=20record?= =?UTF-8?q?=20=ED=83=80=EC=9E=85=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20Long=20=ED=83=80=EC=9E=85=20=ED=99=9C=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=97=AC=20null=20=EA=B0=92=20=ED=97=88=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment/dto/CommentCreateRequest.java | 23 +++++-------------- .../comment/service/CommentService.java | 7 +++--- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java b/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java index c16c77323..8cf57e360 100644 --- a/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java +++ b/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java @@ -3,26 +3,15 @@ import com.example.solidconnection.comment.domain.Comment; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.siteuser.domain.SiteUser; -import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; -import lombok.Getter; - -@Getter -public class CommentCreateRequest { - - @NotBlank(message = "댓글 내용은 빈 값일 수 없습니다.") - @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") - String content; - - @Nullable - Long parentId; - - public CommentCreateRequest(String content, @Nullable Long parentId) { - this.content = content; - this.parentId = parentId; - } +public record CommentCreateRequest( + @NotBlank(message = "댓글 내용은 빈 값일 수 없습니다.") + @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") + String content, + Long parentId +) { public Comment toEntity(SiteUser siteUser, Post post, Comment parentComment) { Comment comment = new Comment( diff --git a/src/main/java/com/example/solidconnection/comment/service/CommentService.java b/src/main/java/com/example/solidconnection/comment/service/CommentService.java index 4fde0c1cf..8003ab26b 100644 --- a/src/main/java/com/example/solidconnection/comment/service/CommentService.java +++ b/src/main/java/com/example/solidconnection/comment/service/CommentService.java @@ -57,9 +57,10 @@ public CommentCreateResponse createComment(String email, Long postId, CommentCre SiteUser siteUser = siteUserRepository.getByEmail(email); Post post = postRepository.getById(postId); - Comment parentComment = Optional.ofNullable(commentCreateRequest.getParentId()) - .map(commentRepository::getById) - .orElse(null); + Comment parentComment = null; + if (commentCreateRequest.parentId() != null) { + parentComment = commentRepository.getById(commentCreateRequest.parentId()); + } Comment createdComment = commentRepository.save(commentCreateRequest.toEntity(siteUser, post, parentComment)); return CommentCreateResponse.from(createdComment); From 19f9073ae8d3a92932c01559380b0debbe44367b Mon Sep 17 00:00:00 2001 From: sewon Date: Sun, 18 Aug 2024 15:09:05 +0900 Subject: [PATCH 15/15] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1=EC=8B=9C=20category=20=EC=A0=84=EC=B2=B4?= =?UTF-8?q?=20=ED=97=88=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/solidconnection/post/service/PostService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/post/service/PostService.java b/src/main/java/com/example/solidconnection/post/service/PostService.java index 12638a317..4f9f77a73 100644 --- a/src/main/java/com/example/solidconnection/post/service/PostService.java +++ b/src/main/java/com/example/solidconnection/post/service/PostService.java @@ -76,7 +76,7 @@ private void validateQuestion(Post post) { } private void validatePostCategory(String category) { - if (!EnumUtils.isValidEnum(PostCategory.class, category)) { + if (!EnumUtils.isValidEnum(PostCategory.class, category) || category.equals(PostCategory.전체.toString())) { throw new CustomException(INVALID_POST_CATEGORY); } }