diff --git a/src/main/java/run/halo/app/controller/admin/api/CommentController.java b/src/main/java/run/halo/app/controller/admin/api/CommentController.java index 2fda240e9..cc085505a 100644 --- a/src/main/java/run/halo/app/controller/admin/api/CommentController.java +++ b/src/main/java/run/halo/app/controller/admin/api/CommentController.java @@ -37,19 +37,22 @@ public class CommentController { @ApiOperation("Lists comments") public Page pageBy(@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable, CommentQuery commentQuery) { - return commentService.pageBy(commentQuery, pageable); + Page commentPage = commentService.pageBy(commentQuery, pageable); + return commentService.convertToWithPostVo(commentPage); } @GetMapping("latest") @ApiOperation("Pages latest comments") public List pageLatest(@RequestParam(name = "top", defaultValue = "10") int top) { - return commentService.pageLatest(top).getContent(); + List content = commentService.pageLatest(top).getContent(); + return commentService.convertToWithPostVo(content); } @GetMapping("status/{status}") public Page pageBy(@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable, @PathVariable("status") CommentStatus status) { - return commentService.pageBy(status, pageable); + Page commentPage = commentService.pageBy(status, pageable); + return commentService.convertToWithPostVo(commentPage); } @PostMapping diff --git a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java index 53341c87c..87a9c1afc 100644 --- a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java +++ b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java @@ -17,7 +17,7 @@ import run.halo.app.model.entity.Category; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.Tag; import run.halo.app.model.enums.PostStatus; -import run.halo.app.model.vo.CommentVO; +import run.halo.app.model.vo.BaseCommentVO; import run.halo.app.model.vo.PostListVO; import run.halo.app.service.*; @@ -116,7 +116,7 @@ public class ContentArchiveController { List categories = postCategoryService.listCategoryBy(post.getId()); List tags = postTagService.listTagsBy(post.getId()); - Page comments = commentService.pageVosBy(post.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort)); + Page comments = commentService.pageVosBy(post.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort)); final int[] pageRainbow = PageUtil.rainbow(cp, comments.getTotalPages(), 3); model.addAttribute("is_post", true); diff --git a/src/main/java/run/halo/app/controller/content/api/PostController.java b/src/main/java/run/halo/app/controller/content/api/PostController.java index 0dd33c957..3f8f4031c 100644 --- a/src/main/java/run/halo/app/controller/content/api/PostController.java +++ b/src/main/java/run/halo/app/controller/content/api/PostController.java @@ -1,13 +1,5 @@ package run.halo.app.controller.content.api; -import run.halo.app.model.dto.post.PostDetailDTO; -import run.halo.app.model.dto.post.PostSimpleDTO; -import run.halo.app.model.enums.PostStatus; -import run.halo.app.model.vo.CommentVO; -import run.halo.app.model.vo.CommentWithParentVO; -import run.halo.app.service.CommentService; -import run.halo.app.service.OptionService; -import run.halo.app.service.PostService; import io.swagger.annotations.ApiOperation; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -16,6 +8,14 @@ import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; import org.springframework.data.web.SortDefault; import org.springframework.web.bind.annotation.*; +import run.halo.app.model.dto.post.PostDetailDTO; +import run.halo.app.model.dto.post.PostSimpleDTO; +import run.halo.app.model.enums.PostStatus; +import run.halo.app.model.vo.BaseCommentVO; +import run.halo.app.model.vo.BaseCommentWithParentVO; +import run.halo.app.service.CommentService; +import run.halo.app.service.OptionService; +import run.halo.app.service.PostService; import static org.springframework.data.domain.Sort.Direction.DESC; @@ -71,17 +71,17 @@ public class PostController { @GetMapping("{postId:\\d+}/comments/tree_view") @ApiOperation("Lists comments with tree view") - public Page listCommentsTree(@PathVariable("postId") Integer postId, - @RequestParam(name = "page", required = false, defaultValue = "0") int page, - @SortDefault(sort = "createTime", direction = DESC) Sort sort) { + public Page listCommentsTree(@PathVariable("postId") Integer postId, + @RequestParam(name = "page", required = false, defaultValue = "0") int page, + @SortDefault(sort = "createTime", direction = DESC) Sort sort) { return commentService.pageVosBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort)); } @GetMapping("{postId:\\d+}/comments/list_view") @ApiOperation("Lists comment with list view") - public Page listComments(@PathVariable("postId") Integer postId, - @RequestParam(name = "page", required = false, defaultValue = "0") int page, - @SortDefault(sort = "createTime", direction = DESC) Sort sort) { + public Page listComments(@PathVariable("postId") Integer postId, + @RequestParam(name = "page", required = false, defaultValue = "0") int page, + @SortDefault(sort = "createTime", direction = DESC) Sort sort) { return commentService.pageWithParentVoBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort)); } diff --git a/src/main/java/run/halo/app/model/dto/BaseCommentDTO.java b/src/main/java/run/halo/app/model/dto/BaseCommentDTO.java new file mode 100644 index 000000000..c10c63304 --- /dev/null +++ b/src/main/java/run/halo/app/model/dto/BaseCommentDTO.java @@ -0,0 +1,44 @@ +package run.halo.app.model.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import run.halo.app.model.dto.base.OutputConverter; +import run.halo.app.model.entity.BaseComment; +import run.halo.app.model.enums.CommentStatus; + +import java.util.Date; + +/** + * Base comment output dto. + * + * @author johnniang + */ +@Data +@ToString +@EqualsAndHashCode +public class BaseCommentDTO implements OutputConverter { + + private Long id; + + private String author; + + private String email; + + private String ipAddress; + + private String gavatarMd5; + + private String content; + + private CommentStatus status; + + private String userAgent; + + private Long parentId; + + private Boolean isAdmin; + + private Date createTime; + +} diff --git a/src/main/java/run/halo/app/model/dto/CommentDTO.java b/src/main/java/run/halo/app/model/dto/CommentDTO.java index b0b4d9ba0..5146e29ef 100644 --- a/src/main/java/run/halo/app/model/dto/CommentDTO.java +++ b/src/main/java/run/halo/app/model/dto/CommentDTO.java @@ -1,14 +1,9 @@ package run.halo.app.model.dto; -import run.halo.app.model.dto.base.OutputConverter; -import run.halo.app.model.entity.Comment; -import run.halo.app.model.enums.CommentStatus; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import java.util.Date; - /** * Comment output dto. * @@ -17,28 +12,6 @@ import java.util.Date; @Data @ToString @EqualsAndHashCode -public class CommentDTO implements OutputConverter { - - private Long id; - - private String author; - - private String email; - - private String ipAddress; - - private String gavatarMd5; - - private String content; - - private CommentStatus status; - - private String userAgent; - - private Long parentId; - - private Boolean isAdmin; - - private Date createTime; +public class CommentDTO extends BaseCommentDTO { } diff --git a/src/main/java/run/halo/app/model/dto/JournalDTO.java b/src/main/java/run/halo/app/model/dto/JournalDTO.java new file mode 100644 index 000000000..bdb1dd5e8 --- /dev/null +++ b/src/main/java/run/halo/app/model/dto/JournalDTO.java @@ -0,0 +1,11 @@ +package run.halo.app.model.dto; + +/** + * Journal dto. + * + * @author johnniang + * @date 19-4-24 + */ +public class JournalDTO extends BaseCommentDTO { + +} diff --git a/src/main/java/run/halo/app/model/dto/post/SheetListDTO.java b/src/main/java/run/halo/app/model/dto/post/SheetListDTO.java new file mode 100644 index 000000000..ee5c27b21 --- /dev/null +++ b/src/main/java/run/halo/app/model/dto/post/SheetListDTO.java @@ -0,0 +1,19 @@ +package run.halo.app.model.dto.post; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Sheet list dto. + * + * @author johnniang + * @date 19-4-24 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class SheetListDTO extends SheetSimpleDTO { + + private Long commentCount; +} diff --git a/src/main/java/run/halo/app/model/vo/BaseCommentVO.java b/src/main/java/run/halo/app/model/vo/BaseCommentVO.java new file mode 100644 index 000000000..7077539f2 --- /dev/null +++ b/src/main/java/run/halo/app/model/vo/BaseCommentVO.java @@ -0,0 +1,22 @@ +package run.halo.app.model.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import run.halo.app.model.dto.BaseCommentDTO; + +import java.util.List; + +/** + * Base comment vo. + * + * @author johnniang + * @date 19-4-24 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class BaseCommentVO extends BaseCommentDTO { + + List children; +} diff --git a/src/main/java/run/halo/app/model/vo/BaseCommentWithParentVO.java b/src/main/java/run/halo/app/model/vo/BaseCommentWithParentVO.java new file mode 100644 index 000000000..71bc08bd1 --- /dev/null +++ b/src/main/java/run/halo/app/model/vo/BaseCommentWithParentVO.java @@ -0,0 +1,34 @@ +package run.halo.app.model.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import run.halo.app.model.dto.BaseCommentDTO; + +/** + * Base comment with parent comment vo. + * + * @author johnniang + * @date 3/31/19 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +@Slf4j +public class BaseCommentWithParentVO extends BaseCommentDTO implements Cloneable { + + /** + * Parent comment. + */ + private BaseCommentWithParentVO parent; + + public BaseCommentWithParentVO clone() { + try { + return (BaseCommentWithParentVO) super.clone(); + } catch (CloneNotSupportedException e) { + log.error("Clone not support exception", e); + return null; + } + } +} diff --git a/src/main/java/run/halo/app/model/vo/CommentVO.java b/src/main/java/run/halo/app/model/vo/CommentVO.java index 210885cae..b823960d8 100644 --- a/src/main/java/run/halo/app/model/vo/CommentVO.java +++ b/src/main/java/run/halo/app/model/vo/CommentVO.java @@ -1,8 +1,8 @@ package run.halo.app.model.vo; -import run.halo.app.model.dto.CommentDTO; import lombok.Data; import lombok.ToString; +import run.halo.app.model.dto.CommentDTO; import java.util.List; @@ -14,6 +14,7 @@ import java.util.List; */ @Data @ToString(callSuper = true) +@Deprecated public class CommentVO extends CommentDTO { private List children; diff --git a/src/main/java/run/halo/app/model/vo/CommentWithParentVO.java b/src/main/java/run/halo/app/model/vo/CommentWithParentVO.java index 1c10bdbf8..bbd3e2f59 100644 --- a/src/main/java/run/halo/app/model/vo/CommentWithParentVO.java +++ b/src/main/java/run/halo/app/model/vo/CommentWithParentVO.java @@ -1,10 +1,10 @@ package run.halo.app.model.vo; -import run.halo.app.model.dto.CommentDTO; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import run.halo.app.model.dto.CommentDTO; /** * Comment list with parent comment vo. @@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j; @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) @Slf4j +@Deprecated public class CommentWithParentVO extends CommentDTO implements Cloneable { /** diff --git a/src/main/java/run/halo/app/repository/CommentRepository.java b/src/main/java/run/halo/app/repository/CommentRepository.java index 6690f17cd..860d284d5 100644 --- a/src/main/java/run/halo/app/repository/CommentRepository.java +++ b/src/main/java/run/halo/app/repository/CommentRepository.java @@ -1,11 +1,8 @@ package run.halo.app.repository; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.lang.NonNull; import run.halo.app.model.entity.Comment; -import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.projection.CommentCountProjection; import run.halo.app.repository.base.BaseCommentRepository; @@ -19,50 +16,9 @@ import java.util.List; */ public interface CommentRepository extends BaseCommentRepository { - /** - * Finds all comments by post ids. - * - * @param postIds post ids must not be null - * @return a list of comment - */ - @NonNull - List findAllByPostIdIn(@NonNull Iterable postIds); - - /** - * Finds all comments by post id. - * - * @param postId post id must not be null - * @return a list of comment - */ - @NonNull - List findAllByPostId(@NonNull Integer postId); - - /** - * Counts comment count by post id collection. - * - * @param postIds post id collection must not be null - * @return a list of comment count - */ - @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from Comment comment where comment.postId in ?1 group by comment.postId") + @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from BaseComment comment where comment.postId in ?1 group by comment.postId") @NonNull + @Override List countByPostIds(@NonNull Iterable postIds); - /** - * Finds comments by post id, comment status. - * - * @param postId post id must not be null - * @param status comment status must not be null - * @return a list of comment - */ - List findAllByPostIdAndStatus(Integer postId, CommentStatus status); - - /** - * Finds comments by post id, comment status. - * - * @param postId post id must not be null - * @param status comment status must not be null - * @param pageable page info must not be null - * @return a page of comment - */ - Page findAllByPostIdAndStatus(Integer postId, CommentStatus status, Pageable pageable); } diff --git a/src/main/java/run/halo/app/repository/JournalRepository.java b/src/main/java/run/halo/app/repository/JournalRepository.java index bf375a688..f774bbfe8 100644 --- a/src/main/java/run/halo/app/repository/JournalRepository.java +++ b/src/main/java/run/halo/app/repository/JournalRepository.java @@ -1,8 +1,13 @@ package run.halo.app.repository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.NonNull; import run.halo.app.model.entity.Journal; +import run.halo.app.model.projection.CommentCountProjection; import run.halo.app.repository.base.BaseCommentRepository; +import java.util.List; + /** * Journal repository. * @@ -11,4 +16,13 @@ import run.halo.app.repository.base.BaseCommentRepository; */ public interface JournalRepository extends BaseCommentRepository { + /** + * Counts comment count by post id collection. + * + * @param postIds post id collection must not be null + * @return a list of comment count + */ + @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from Journal comment where comment.postId in ?1 group by comment.postId") + @NonNull + List countByPostIds(@NonNull Iterable postIds); } diff --git a/src/main/java/run/halo/app/repository/SheetCommentRepository.java b/src/main/java/run/halo/app/repository/SheetCommentRepository.java index 0d099c1a1..39a4fa52f 100644 --- a/src/main/java/run/halo/app/repository/SheetCommentRepository.java +++ b/src/main/java/run/halo/app/repository/SheetCommentRepository.java @@ -1,8 +1,13 @@ package run.halo.app.repository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.NonNull; import run.halo.app.model.entity.SheetComment; +import run.halo.app.model.projection.CommentCountProjection; import run.halo.app.repository.base.BaseCommentRepository; +import java.util.List; + /** * Sheet comment repository. * @@ -11,4 +16,8 @@ import run.halo.app.repository.base.BaseCommentRepository; */ public interface SheetCommentRepository extends BaseCommentRepository { + @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from SheetComment comment where comment.postId in ?1 group by comment.postId") + @NonNull + @Override + List countByPostIds(@NonNull Iterable postIds); } diff --git a/src/main/java/run/halo/app/repository/base/BaseCommentRepository.java b/src/main/java/run/halo/app/repository/base/BaseCommentRepository.java index 8632904e4..9407c6712 100644 --- a/src/main/java/run/halo/app/repository/base/BaseCommentRepository.java +++ b/src/main/java/run/halo/app/repository/base/BaseCommentRepository.java @@ -3,10 +3,14 @@ package run.halo.app.repository.base; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.NoRepositoryBean; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import run.halo.app.model.entity.BaseComment; import run.halo.app.model.enums.CommentStatus; +import run.halo.app.model.projection.CommentCountProjection; + +import java.util.List; /** * Base comment repository. @@ -14,7 +18,8 @@ import run.halo.app.model.enums.CommentStatus; * @author johnniang * @date 19-4-24 */ -public interface BaseCommentRepository extends BaseRepository, JpaSpecificationExecutor { +@NoRepositoryBean +public interface BaseCommentRepository extends BaseRepository, JpaSpecificationExecutor { /** * Finds all comments by status. @@ -24,7 +29,55 @@ public interface BaseCommentRepository extends BaseR * @return a page of comment */ @NonNull - Page findAllByStatus(@Nullable CommentStatus status, @NonNull Pageable pageable); + Page findAllByStatus(@Nullable CommentStatus status, @NonNull Pageable pageable); + /** + * Finds all comments by post ids. + * + * @param postIds post ids must not be null + * @return a list of comment + */ + @NonNull + List findAllByPostIdIn(@NonNull Iterable postIds); + + /** + * Finds all comments by post id. + * + * @param postId post id must not be null + * @return a list of comment + */ + @NonNull + List findAllByPostId(@NonNull Integer postId); + + /** + * Counts comment count by post id collection. + * + * @param postIds post id collection must not be null + * @return a list of comment count + */ +// @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from BaseComment comment where comment.postId in ?1 group by comment.postId") + @NonNull + List countByPostIds(@NonNull Iterable postIds); + + /** + * Finds comments by post id, comment status. + * + * @param postId post id must not be null + * @param status comment status must not be null + * @return a list of comment + */ + @NonNull + List findAllByPostIdAndStatus(Integer postId, CommentStatus status); + + /** + * Finds comments by post id, comment status. + * + * @param postId post id must not be null + * @param status comment status must not be null + * @param pageable page info must not be null + * @return a page of comment + */ + @NonNull + Page findAllByPostIdAndStatus(Integer postId, CommentStatus status, Pageable pageable); } diff --git a/src/main/java/run/halo/app/service/CommentService.java b/src/main/java/run/halo/app/service/CommentService.java index a9157176a..667aa3ac2 100644 --- a/src/main/java/run/halo/app/service/CommentService.java +++ b/src/main/java/run/halo/app/service/CommentService.java @@ -1,82 +1,21 @@ package run.halo.app.service; import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import run.halo.app.model.entity.Comment; -import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.params.CommentParam; -import run.halo.app.model.params.CommentQuery; -import run.halo.app.model.vo.CommentVO; -import run.halo.app.model.vo.CommentWithParentVO; import run.halo.app.model.vo.CommentWithPostVO; -import run.halo.app.service.base.CrudService; +import run.halo.app.service.base.BaseCommentService; -import java.util.Collection; import java.util.List; -import java.util.Map; /** * Comment service. * * @author johnniang */ -public interface CommentService extends CrudService { - - /** - * %d: parent commentator id - * %s: parent commentator author name - * %s: comment content - */ - String COMMENT_TEMPLATE = "@%s %s"; - - /** - * Lists latest comments. - * - * @param top top number must not be less than 0 - * @return a page of comments - */ - @NonNull - Page pageLatest(int top); - - /** - * Pages comments. - * - * @param status comment status must not be null - * @param pageable page info must not be null - * @return a page of comment - */ - @NonNull - Page pageBy(@NonNull CommentStatus status, @NonNull Pageable pageable); - - /** - * Pages comments. - * - * @param commentQuery comment query must not be null - * @param pageable page info must not be null - * @return a page of comment - */ - @NonNull - Page pageBy(@NonNull CommentQuery commentQuery, @NonNull Pageable pageable); - - /** - * Lists comments by post id. - * - * @param postId post id must not be null - * @return a list of comment - */ - @NonNull - List listBy(@NonNull Integer postId); - - /** - * Counts by post id collection. - * - * @param postIds post id collection - * @return a count map, key: post id, value: comment count - */ - @NonNull - Map countByPostIds(@Nullable Collection postIds); +public interface CommentService extends BaseCommentService { /** * Creates a comment by comment param. @@ -88,32 +27,20 @@ public interface CommentService extends CrudService { Comment createBy(@NonNull CommentParam commentParam); /** - * Lists comment vos by post id. + * Converts to with post vo. * - * @param postId post id must not be null - * @param pageable page info must not be null - * @return a page of comment vo + * @param commentPage comment page must not be null + * @return a page of comment with post vo */ @NonNull - Page pageVosBy(@NonNull Integer postId, @NonNull Pageable pageable); + Page convertToWithPostVo(@NonNull Page commentPage); /** - * Lists comment with parent vo. + * Converts to with post vo * - * @param postId post id must not be null - * @param pageable page info must not be null - * @return a page of comment with parent vo. + * @param comments comment list + * @return a list of comment with post vo */ @NonNull - Page pageWithParentVoBy(@NonNull Integer postId, @NonNull Pageable pageable); - - /** - * Updates comment status. - * - * @param commentId comment id must not be null - * @param status comment status must not be null - * @return updated comment - */ - @NonNull - Comment updateStatus(@NonNull Long commentId, @NonNull CommentStatus status); + List convertToWithPostVo(@Nullable List comments); } diff --git a/src/main/java/run/halo/app/service/SheetService.java b/src/main/java/run/halo/app/service/SheetService.java index ef631fa10..bd4f510f3 100644 --- a/src/main/java/run/halo/app/service/SheetService.java +++ b/src/main/java/run/halo/app/service/SheetService.java @@ -4,6 +4,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.lang.NonNull; import run.halo.app.model.dto.post.SheetDetailDTO; +import run.halo.app.model.dto.post.SheetListDTO; import run.halo.app.model.entity.Sheet; import run.halo.app.model.enums.PostStatus; import run.halo.app.service.base.CrudService; @@ -61,4 +62,13 @@ public interface SheetService extends CrudService { */ @NonNull Sheet getBy(@NonNull PostStatus status, @NonNull String url); + + /** + * Converts to list dto page. + * + * @param sheetPage sheet page must not be nulls + * @return a page of sheet list dto + */ + @NonNull + Page convertToListDto(@NonNull Page sheetPage); } diff --git a/src/main/java/run/halo/app/service/base/BaseCommentService.java b/src/main/java/run/halo/app/service/base/BaseCommentService.java new file mode 100644 index 000000000..4020a5a74 --- /dev/null +++ b/src/main/java/run/halo/app/service/base/BaseCommentService.java @@ -0,0 +1,119 @@ +package run.halo.app.service.base; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import run.halo.app.model.entity.BaseComment; +import run.halo.app.model.enums.CommentStatus; +import run.halo.app.model.params.CommentQuery; +import run.halo.app.model.vo.BaseCommentVO; +import run.halo.app.model.vo.BaseCommentWithParentVO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * Base comment service interface. + * + * @author johnniang + * @date 19-4-24 + */ +public interface BaseCommentService extends CrudService { + + /** + * %d: parent commentator id + * %s: parent commentator author name + * %s: comment content + */ + @Deprecated + String COMMENT_TEMPLATE = "@%s %s"; + + /** + * Lists comments by post id. + * + * @param postId post id must not be null + * @return a list of comment + */ + @NonNull + List listBy(@NonNull Integer postId); + + /** + * Lists latest comments. + * + * @param top top number must not be less than 0 + * @return a page of comments + */ + @NonNull + Page pageLatest(int top); + + /** + * Pages comments. + * + * @param status comment status must not be null + * @param pageable page info must not be null + * @return a page of comment + */ + @NonNull + Page pageBy(@NonNull CommentStatus status, @NonNull Pageable pageable); + + /** + * Pages comments. + * + * @param commentQuery comment query must not be null + * @param pageable page info must not be null + * @return a page of comment + */ + @NonNull + Page pageBy(@NonNull CommentQuery commentQuery, @NonNull Pageable pageable); + + /** + * Lists comment vos by post id. + * + * @param postId post id must not be null + * @param pageable page info must not be null + * @return a page of comment vo + */ + @NonNull + Page pageVosBy(@NonNull Integer postId, @NonNull Pageable pageable); + + /** + * Lists comment with parent vo. + * + * @param postId post id must not be null + * @param pageable page info must not be null + * @return a page of comment with parent vo. + */ + @NonNull + Page pageWithParentVoBy(@NonNull Integer postId, @NonNull Pageable pageable); + + /** + * Counts by post id collection. + * + * @param postIds post id collection + * @return a count map, key: post id, value: comment count + */ + @NonNull + Map countByPostIds(@Nullable Collection postIds); + + /** + * Creates a comment by comment param. + * + * @param COMMENT comment must not be null + * @return created comment + */ + @NonNull + COMMENT createBy(@NonNull COMMENT COMMENT); + + /** + * Updates comment status. + * + * @param commentId comment id must not be null + * @param status comment status must not be null + * @return updated comment + */ + @NonNull + COMMENT updateStatus(@NonNull Long commentId, @NonNull CommentStatus status); +} diff --git a/src/main/java/run/halo/app/service/base/BaseCommentServiceImpl.java b/src/main/java/run/halo/app/service/base/BaseCommentServiceImpl.java new file mode 100644 index 000000000..bd4279e43 --- /dev/null +++ b/src/main/java/run/halo/app/service/base/BaseCommentServiceImpl.java @@ -0,0 +1,386 @@ +package run.halo.app.service.base; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.http.HttpHeaders; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import run.halo.app.event.comment.CommentNewEvent; +import run.halo.app.event.comment.CommentPassEvent; +import run.halo.app.event.comment.CommentReplyEvent; +import run.halo.app.exception.NotFoundException; +import run.halo.app.model.entity.BaseComment; +import run.halo.app.model.enums.CommentStatus; +import run.halo.app.model.params.CommentQuery; +import run.halo.app.model.projection.CommentCountProjection; +import run.halo.app.model.properties.CommentProperties; +import run.halo.app.model.support.CommentPage; +import run.halo.app.model.vo.BaseCommentVO; +import run.halo.app.model.vo.BaseCommentWithParentVO; +import run.halo.app.model.vo.CommentWithParentVO; +import run.halo.app.repository.PostRepository; +import run.halo.app.repository.base.BaseCommentRepository; +import run.halo.app.security.authentication.Authentication; +import run.halo.app.security.context.SecurityContextHolder; +import run.halo.app.service.OptionService; +import run.halo.app.utils.ServiceUtils; +import run.halo.app.utils.ServletUtils; + +import javax.persistence.criteria.Predicate; +import java.util.*; + +/** + * Base comment service implementation. + * + * @author johnniang + * @date 19-4-24 + */ +@Slf4j +public abstract class BaseCommentServiceImpl extends AbstractCrudService implements BaseCommentService { + + private final BaseCommentRepository baseCommentRepository; + + protected final PostRepository postRepository; + + protected final OptionService optionService; + + protected final ApplicationEventPublisher eventPublisher; + + public BaseCommentServiceImpl(BaseCommentRepository baseCommentRepository, + PostRepository postRepository, + OptionService optionService, + ApplicationEventPublisher eventPublisher) { + super(baseCommentRepository); + this.baseCommentRepository = baseCommentRepository; + this.postRepository = postRepository; + this.optionService = optionService; + this.eventPublisher = eventPublisher; + } + + @Override + public List listBy(Integer postId) { + Assert.notNull(postId, "Post id must not be null"); + + return baseCommentRepository.findAllByPostId(postId); + } + + @Override + public Page pageLatest(int top) { + Assert.isTrue(top > 0, "Top number must not be less than 0"); + + // Build page request + PageRequest latestPageable = PageRequest.of(0, top, Sort.by(Sort.Direction.DESC, "createTime")); + + return listAll(latestPageable); + } + + @Override + public Page pageBy(CommentStatus status, Pageable pageable) { + + Assert.notNull(status, "Comment status must not be null"); + Assert.notNull(pageable, "Page info must not be null"); + + // Find all + return baseCommentRepository.findAllByStatus(status, pageable); + } + + @Override + public Page pageBy(CommentQuery commentQuery, Pageable pageable) { + Assert.notNull(pageable, "Page info must not be null"); + + return baseCommentRepository.findAll(buildSpecByQuery(commentQuery), pageable); + } + + @Override + public Page pageVosBy(Integer postId, Pageable pageable) { + Assert.notNull(postId, "Post id must not be null"); + Assert.notNull(pageable, "Page info must not be null"); + + log.debug("Getting comment tree view of post: [{}], page info: [{}]", postId, pageable); + + // List all the top comments (Caution: This list will be cleared) + List comments = baseCommentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED); + + // Init the top virtual comment + BaseCommentVO topVirtualComment = new BaseCommentVO(); + topVirtualComment.setId(0L); + topVirtualComment.setChildren(new LinkedList<>()); + + Comparator commentVOComparator = buildCommentComparator(pageable.getSortOr(Sort.by(Sort.Direction.DESC, "createTime"))); + + // Concrete the comment tree + concreteTree(topVirtualComment, new LinkedList<>(comments), commentVOComparator); + + List topComments = topVirtualComment.getChildren(); + + List pageContent; + + // Calc the shear index + int startIndex = pageable.getPageNumber() * pageable.getPageSize(); + if (startIndex >= topComments.size() || startIndex < 0) { + pageContent = Collections.emptyList(); + } else { + int endIndex = startIndex + pageable.getPageSize(); + if (endIndex > topComments.size()) { + endIndex = topComments.size(); + } + + log.debug("Top comments size: [{}]", topComments.size()); + log.debug("Start index: [{}]", startIndex); + log.debug("End index: [{}]", endIndex); + + pageContent = topComments.subList(startIndex, endIndex); + } + + return new CommentPage<>(pageContent, pageable, topComments.size(), comments.size()); + + } + + @Override + public Page pageWithParentVoBy(Integer postId, Pageable pageable) { + Assert.notNull(postId, "Post id must not be null"); + Assert.notNull(pageable, "Page info must not be null"); + + log.debug("Getting comment list view of post: [{}], page info: [{}]", postId, pageable); + + // List all the top comments (Caution: This list will be cleared) + Page commentPage = baseCommentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED, pageable); + + // Get all comments + List comments = commentPage.getContent(); + + // Get all comment parent ids + Set parentIds = ServiceUtils.fetchProperty(comments, COMMENT::getParentId); + + // Get all parent comments + List parentComments = baseCommentRepository.findAllByIdIn(parentIds, pageable.getSort()); + + // Convert to comment map (Key: comment id, value: comment) + Map parentCommentMap = ServiceUtils.convertToMap(parentComments, COMMENT::getId); + + Map parentCommentVoMap = new HashMap<>(parentCommentMap.size()); + + // Convert to comment page + return commentPage.map(comment -> { + // Convert to with parent vo + BaseCommentWithParentVO commentWithParentVO = new BaseCommentWithParentVO().convertFrom(comment); + + // Get parent comment vo from cache + BaseCommentWithParentVO parentCommentVo = parentCommentVoMap.get(comment.getParentId()); + + if (parentCommentVo == null) { + // Get parent comment + COMMENT parentComment = parentCommentMap.get(comment.getParentId()); + + if (parentComment != null) { + // Convert to parent comment vo + parentCommentVo = new CommentWithParentVO().convertFrom(parentComment); + // Cache the parent comment vo + parentCommentVoMap.put(parentComment.getId(), parentCommentVo); + } + } + + // Set parent + commentWithParentVO.setParent(parentCommentVo == null ? null : parentCommentVo.clone()); + + return commentWithParentVO; + }); + } + + @Override + public Map countByPostIds(Collection postIds) { + if (CollectionUtils.isEmpty(postIds)) { + return Collections.emptyMap(); + } + + // Get all comment counts + List commentCountProjections = baseCommentRepository.countByPostIds(postIds); + + return ServiceUtils.convertToMap(commentCountProjections, CommentCountProjection::getPostId, CommentCountProjection::getCount); + } + + @Override + public COMMENT createBy(COMMENT COMMENT) { + Assert.notNull(COMMENT, "Domain must not be null"); + + // Check post id + boolean isPostExist = postRepository.existsById(COMMENT.getPostId()); + if (!isPostExist) { + throw new NotFoundException("The post with id " + COMMENT.getPostId() + " was not found"); + } + + // Check parent id + if (!ServiceUtils.isEmptyId(COMMENT.getParentId())) { + mustExistById(COMMENT.getParentId()); + } + + // Check user login status and set this field + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + // Set some default values + COMMENT.setIpAddress(ServletUtils.getRequestIp()); + COMMENT.setUserAgent(ServletUtils.getHeaderIgnoreCase(HttpHeaders.USER_AGENT)); + COMMENT.setGavatarMd5(DigestUtils.md5Hex(COMMENT.getEmail())); + + if (authentication != null) { + // Comment of blogger + COMMENT.setIsAdmin(true); + COMMENT.setStatus(CommentStatus.PUBLISHED); + } else { + // Comment of guest + // Handle comment status + Boolean needAudit = optionService.getByPropertyOrDefault(CommentProperties.NEW_NEED_CHECK, Boolean.class, true); + COMMENT.setStatus(needAudit ? CommentStatus.AUDITING : CommentStatus.PUBLISHED); + } + + // Create comment + COMMENT createdComment = create(COMMENT); + + if (ServiceUtils.isEmptyId(createdComment.getParentId())) { + if (authentication == null) { + // New comment of guest + eventPublisher.publishEvent(new CommentNewEvent(this, createdComment.getId())); + } + } else { + // Reply comment + eventPublisher.publishEvent(new CommentReplyEvent(this, createdComment.getId())); + } + + return createdComment; + } + + @Override + public COMMENT updateStatus(Long commentId, CommentStatus status) { + Assert.notNull(commentId, "Comment id must not be null"); + Assert.notNull(status, "Comment status must not be null"); + + // Get comment by id + COMMENT comment = getById(commentId); + + // Set comment status + comment.setStatus(status); + + // Update comment + COMMENT updatedComment = update(comment); + + if (CommentStatus.PUBLISHED.equals(status)) { + // Pass a comment + eventPublisher.publishEvent(new CommentPassEvent(this, commentId)); + } + + return updatedComment; + } + + @NonNull + private Specification buildSpecByQuery(@NonNull CommentQuery commentQuery) { + Assert.notNull(commentQuery, "Comment query must not be null"); + + return (Specification) (root, query, criteriaBuilder) -> { + List predicates = new LinkedList<>(); + + if (commentQuery.getStatus() != null) { + predicates.add(criteriaBuilder.equal(root.get("status"), commentQuery.getStatus())); + } + + if (commentQuery.getKeyword() != null) { + + String likeCondition = String.format("%%%s%%", StringUtils.strip(commentQuery.getKeyword())); + + Predicate authorLike = criteriaBuilder.like(root.get("author"), likeCondition); + Predicate contentLike = criteriaBuilder.like(root.get("content"), likeCondition); + Predicate emailLike = criteriaBuilder.like(root.get("email"), likeCondition); + + predicates.add(criteriaBuilder.or(authorLike, contentLike, emailLike)); + } + + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); + }; + } + + /** + * Builds a comment comparator. + * + * @param sort sort info + * @return comment comparator + */ + private Comparator buildCommentComparator(Sort sort) { + return (currentComment, toCompareComment) -> { + Assert.notNull(currentComment, "Current comment must not be null"); + Assert.notNull(toCompareComment, "Comment to compare must not be null"); + + // Get sort order + Sort.Order order = sort.filter(anOrder -> anOrder.getProperty().equals("createTime")) + .get() + .findFirst() + .orElseGet(() -> Sort.Order.desc("createTime")); + + // Init sign + int sign = order.getDirection().isAscending() ? 1 : -1; + + // Compare createTime property + return sign * currentComment.getCreateTime().compareTo(toCompareComment.getCreateTime()); + }; + } + + /** + * Concretes comment tree. + * + * @param parentComment parent comment vo must not be null + * @param comments comment list must not null + * @param commentComparator comment vo comparator + */ + private void concreteTree(@NonNull BaseCommentVO parentComment, + @Nullable Collection comments, + @NonNull Comparator commentComparator) { + Assert.notNull(parentComment, "Parent comment must not be null"); + Assert.notNull(commentComparator, "Comment comparator must not be null"); + + if (CollectionUtils.isEmpty(comments)) { + return; + } + + List children = new LinkedList<>(); + + comments.forEach(comment -> { + if (parentComment.getId().equals(comment.getParentId())) { + // Stage the child comment + children.add(comment); + + // Convert to comment vo + BaseCommentVO commentVO = new BaseCommentVO().convertFrom(comment); + + // Add additional content + if (commentVO.getParentId() > 0) { + // TODO Provide an optional additional content + commentVO.setContent(String.format(COMMENT_TEMPLATE, parentComment.getId(), parentComment.getAuthor(), commentVO.getContent())); + } + + // Init children container + if (parentComment.getChildren() == null) { + parentComment.setChildren(new LinkedList<>()); + } + + parentComment.getChildren().add(commentVO); + } + }); + + // Remove all children + comments.removeAll(children); + + if (!CollectionUtils.isEmpty(parentComment.getChildren())) { + // Recursively concrete the children + parentComment.getChildren().forEach(childComment -> concreteTree(childComment, comments, commentComparator)); + // Sort the children + parentComment.getChildren().sort(commentComparator); + } + } +} diff --git a/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java b/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java index 5db745841..a6fe9b288 100644 --- a/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java @@ -1,36 +1,19 @@ package run.halo.app.service.impl; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.domain.*; -import org.springframework.data.domain.Sort.Order; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.http.HttpHeaders; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.web.util.HtmlUtils; -import run.halo.app.event.comment.CommentNewEvent; -import run.halo.app.event.comment.CommentPassEvent; -import run.halo.app.event.comment.CommentReplyEvent; -import run.halo.app.exception.NotFoundException; import run.halo.app.model.dto.post.PostMinimalDTO; import run.halo.app.model.entity.Comment; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.User; -import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.params.CommentParam; -import run.halo.app.model.params.CommentQuery; -import run.halo.app.model.projection.CommentCountProjection; import run.halo.app.model.properties.BlogProperties; -import run.halo.app.model.properties.CommentProperties; -import run.halo.app.model.support.CommentPage; -import run.halo.app.model.vo.CommentVO; -import run.halo.app.model.vo.CommentWithParentVO; import run.halo.app.model.vo.CommentWithPostVO; import run.halo.app.repository.CommentRepository; import run.halo.app.repository.PostRepository; @@ -38,13 +21,14 @@ import run.halo.app.security.authentication.Authentication; import run.halo.app.security.context.SecurityContextHolder; import run.halo.app.service.CommentService; import run.halo.app.service.OptionService; -import run.halo.app.service.base.AbstractCrudService; +import run.halo.app.service.base.BaseCommentServiceImpl; import run.halo.app.utils.ServiceUtils; -import run.halo.app.utils.ServletUtils; import run.halo.app.utils.ValidationUtils; -import javax.persistence.criteria.Predicate; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; /** @@ -55,99 +39,16 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class CommentServiceImpl extends AbstractCrudService implements CommentService { +public class CommentServiceImpl extends BaseCommentServiceImpl implements CommentService { private final CommentRepository commentRepository; - private final PostRepository postRepository; - - private final OptionService optionService; - - private final ApplicationEventPublisher eventPublisher; - public CommentServiceImpl(CommentRepository commentRepository, PostRepository postRepository, OptionService optionService, ApplicationEventPublisher eventPublisher) { - super(commentRepository); + super(commentRepository, postRepository, optionService, eventPublisher); this.commentRepository = commentRepository; - this.postRepository = postRepository; - this.optionService = optionService; - this.eventPublisher = eventPublisher; - } - - @Override - public Page pageLatest(int top) { - Assert.isTrue(top > 0, "Top number must not be less than 0"); - - // Build page request - PageRequest latestPageable = PageRequest.of(0, top, Sort.by(Sort.Direction.DESC, "createTime")); - - return convertBy(listAll(latestPageable)); - } - - @Override - public Page pageBy(CommentStatus status, Pageable pageable) { - Assert.notNull(status, "Comment status must not be null"); - Assert.notNull(pageable, "Page info must not be null"); - - // Find all - Page commentPage = commentRepository.findAllByStatus(status, pageable); - - return convertBy(commentPage); - } - - @Override - public Page pageBy(CommentQuery commentQuery, Pageable pageable) { - Assert.notNull(commentQuery, "Comment query must not be null"); - Assert.notNull(pageable, "Page info must not be null"); - Page commentPage = commentRepository.findAll(buildSpecByQuery(commentQuery), pageable); - return convertBy(commentPage); - } - - @NonNull - private Specification buildSpecByQuery(@NonNull CommentQuery commentQuery) { - Assert.notNull(commentQuery, "Comment query must not be null"); - - return (Specification) (root, query, criteriaBuilder) -> { - List predicates = new LinkedList<>(); - - if (commentQuery.getStatus() != null) { - predicates.add(criteriaBuilder.equal(root.get("status"), commentQuery.getStatus())); - } - - if (commentQuery.getKeyword() != null) { - - String likeCondition = String.format("%%%s%%", StringUtils.strip(commentQuery.getKeyword())); - - Predicate authorLike = criteriaBuilder.like(root.get("author"), likeCondition); - Predicate contentLike = criteriaBuilder.like(root.get("content"), likeCondition); - Predicate emailLike = criteriaBuilder.like(root.get("email"), likeCondition); - - predicates.add(criteriaBuilder.or(authorLike, contentLike, emailLike)); - } - - return query.where(predicates.toArray(new Predicate[0])).getRestriction(); - }; - } - - @Override - public List listBy(Integer postId) { - Assert.notNull(postId, "Post id must not be null"); - - return commentRepository.findAllByPostId(postId); - } - - @Override - public Map countByPostIds(Collection postIds) { - if (CollectionUtils.isEmpty(postIds)) { - return Collections.emptyMap(); - } - - // Get all comment counts - List commentCountProjections = commentRepository.countByPostIds(postIds); - - return ServiceUtils.convertToMap(commentCountProjections, CommentCountProjection::getPostId, CommentCountProjection::getCount); } @Override @@ -167,264 +68,20 @@ public class CommentServiceImpl extends AbstractCrudService imple // Validate the comment param manually ValidationUtils.validate(commentParam); - // Check post id - boolean isPostExist = postRepository.existsById(commentParam.getPostId()); - if (!isPostExist) { - throw new NotFoundException("The post with id " + commentParam.getPostId() + " was not found"); - } - - // Check parent id - if (!ServiceUtils.isEmptyId(commentParam.getParentId())) { - mustExistById(commentParam.getParentId()); - } - // Convert to comment - Comment comment = commentParam.convertTo(); - - // Set some default values - comment.setIpAddress(ServletUtils.getRequestIp()); - comment.setUserAgent(ServletUtils.getHeaderIgnoreCase(HttpHeaders.USER_AGENT)); - comment.setGavatarMd5(DigestUtils.md5Hex(comment.getEmail())); - - if (authentication != null) { - // Comment of blogger - comment.setIsAdmin(true); - comment.setStatus(CommentStatus.PUBLISHED); - } else { - // Comment of guest - // Handle comment status - Boolean needAudit = optionService.getByPropertyOrDefault(CommentProperties.NEW_NEED_CHECK, Boolean.class, true); - comment.setStatus(needAudit ? CommentStatus.AUDITING : CommentStatus.PUBLISHED); - } - - // Create comment - Comment createdComment = create(comment); - - if (ServiceUtils.isEmptyId(createdComment.getParentId())) { - if (authentication == null) { - // New comment of guest - eventPublisher.publishEvent(new CommentNewEvent(this, createdComment.getId())); - } - } else { - // Reply comment - eventPublisher.publishEvent(new CommentReplyEvent(this, createdComment.getId())); - } - - return createdComment; + return createBy(commentParam.convertTo()); } @Override - public Page pageVosBy(Integer postId, Pageable pageable) { - Assert.notNull(postId, "Post id must not be null"); - Assert.notNull(pageable, "Page info must not be null"); - - log.debug("Getting comment tree view of post: [{}], page info: [{}]", postId, pageable); - - // List all the top comments (Caution: This list will be cleared) - List comments = commentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED); - - // Init the top virtual comment - CommentVO topVirtualComment = new CommentVO(); - topVirtualComment.setId(0L); - topVirtualComment.setChildren(new LinkedList<>()); - - // Concrete the comment tree - concreteTree(topVirtualComment, new LinkedList<>(comments), buildCommentComparator(pageable.getSortOr(Sort.by(Sort.Direction.DESC, "createTime")))); - - List topComments = topVirtualComment.getChildren(); - - List pageContent; - - // Calc the shear index - int startIndex = pageable.getPageNumber() * pageable.getPageSize(); - if (startIndex >= topComments.size() || startIndex < 0) { - pageContent = Collections.emptyList(); - } else { - int endIndex = startIndex + pageable.getPageSize(); - if (endIndex > topComments.size()) { - endIndex = topComments.size(); - } - - log.debug("Top comments size: [{}]", topComments.size()); - log.debug("Start index: [{}]", startIndex); - log.debug("End index: [{}]", endIndex); - - pageContent = topComments.subList(startIndex, endIndex); - } - - return new CommentPage<>(pageContent, pageable, topComments.size(), comments.size()); - } - - @Override - public Page pageWithParentVoBy(Integer postId, Pageable pageable) { - Assert.notNull(postId, "Post id must not be null"); - Assert.notNull(pageable, "Page info must not be null"); - - log.debug("Getting comment list view of post: [{}], page info: [{}]", postId, pageable); - - // List all the top comments (Caution: This list will be cleared) - Page commentPage = commentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED, pageable); - - // Get all comments - List comments = commentPage.getContent(); - - // Get all comment parent ids - Set parentIds = ServiceUtils.fetchProperty(comments, Comment::getParentId); - - // Get all parent comments - List parentComments = commentRepository.findAllByIdIn(parentIds, pageable.getSort()); - - // Convert to comment map (Key: comment id, value: comment) - Map parentCommentMap = ServiceUtils.convertToMap(parentComments, Comment::getId); - - Map parentCommentVoMap = new HashMap<>(parentCommentMap.size()); - - // Convert to comment page - return commentPage.map(comment -> { - // Convert to with parent vo - CommentWithParentVO commentWithParentVO = new CommentWithParentVO().convertFrom(comment); - - // Get parent comment vo from cache - CommentWithParentVO parentCommentVo = parentCommentVoMap.get(comment.getParentId()); - - if (parentCommentVo == null) { - // Get parent comment - Comment parentComment = parentCommentMap.get(comment.getParentId()); - - if (parentComment != null) { - // Convert to parent comment vo - parentCommentVo = new CommentWithParentVO().convertFrom(parentComment); - // Cache the parent comment vo - parentCommentVoMap.put(parentComment.getId(), parentCommentVo); - } - } - - // Set parent - commentWithParentVO.setParent(parentCommentVo == null ? null : parentCommentVo.clone()); - - return commentWithParentVO; - }); - } - - @Override - public Comment updateStatus(Long commentId, CommentStatus status) { - Assert.notNull(commentId, "Comment id must not be null"); - Assert.notNull(status, "Comment status must not be null"); - - // Get comment by id - Comment comment = getById(commentId); - - // Set comment status - comment.setStatus(status); - - // Update comment - Comment updatedComment = update(comment); - - if (CommentStatus.PUBLISHED.equals(status)) { - // Pass a comment - eventPublisher.publishEvent(new CommentPassEvent(this, commentId)); - } - - return updatedComment; - } - - /** - * Builds a comment comparator. - * - * @param sort sort info - * @return comment comparator - */ - private Comparator buildCommentComparator(Sort sort) { - return (currentComment, toCompareComment) -> { - Assert.notNull(currentComment, "Current comment must not be null"); - Assert.notNull(toCompareComment, "Comment to compare must not be null"); - - // Get sort order - Order order = sort.filter(anOrder -> anOrder.getProperty().equals("createTime")) - .get() - .findFirst() - .orElseGet(() -> Order.desc("createTime")); - - // Init sign - int sign = order.getDirection().isAscending() ? 1 : -1; - - // Compare createTime property - return sign * currentComment.getCreateTime().compareTo(toCompareComment.getCreateTime()); - }; - } - - /** - * Concretes comment tree. - * - * @param parentComment parent comment vo must not be null - * @param comments comment list must not null - * @param commentComparator comment vo comparator - */ - private void concreteTree(@NonNull CommentVO parentComment, Collection comments, @NonNull Comparator commentComparator) { - Assert.notNull(parentComment, "Parent comment must not be null"); - Assert.notNull(commentComparator, "Comment comparator must not be null"); - - if (CollectionUtils.isEmpty(comments)) { - return; - } - - List children = new LinkedList<>(); - - comments.forEach(comment -> { - if (parentComment.getId().equals(comment.getParentId())) { - // Stage the child comment - children.add(comment); - - // Convert to comment vo - CommentVO commentVO = new CommentVO().convertFrom(comment); - - // Add additional content - if (commentVO.getParentId() > 0) { - // TODO Provide an optional additional content - commentVO.setContent(String.format(COMMENT_TEMPLATE, parentComment.getId(), parentComment.getAuthor(), commentVO.getContent())); - } - - // Init children container - if (parentComment.getChildren() == null) { - parentComment.setChildren(new LinkedList<>()); - } - - parentComment.getChildren().add(commentVO); - } - }); - - // Remove all children - comments.removeAll(children); - - if (!CollectionUtils.isEmpty(parentComment.getChildren())) { - // Recursively concrete the children - parentComment.getChildren().forEach(childComment -> concreteTree(childComment, comments, commentComparator)); - // Sort the children - parentComment.getChildren().sort(commentComparator); - } - } - - /** - * Converts to comment vo page. - * - * @param commentPage comment page must not be null - * @return a page of comment vo - */ - @NonNull - private Page convertBy(@NonNull Page commentPage) { + public Page convertToWithPostVo(Page commentPage) { Assert.notNull(commentPage, "Comment page must not be null"); - return new PageImpl<>(convertBy(commentPage.getContent()), commentPage.getPageable(), commentPage.getTotalElements()); + return new PageImpl<>(convertToWithPostVo(commentPage.getContent()), commentPage.getPageable(), commentPage.getTotalElements()); + } - /** - * Converts to comment vo list. - * - * @param comments comment list - * @return a list of comment vo - */ - @NonNull - private List convertBy(@Nullable List comments) { + @Override + public List convertToWithPostVo(List comments) { if (CollectionUtils.isEmpty(comments)) { return Collections.emptyList(); } @@ -446,8 +103,4 @@ public class CommentServiceImpl extends AbstractCrudService imple }).collect(Collectors.toList()); } - private String formatContent(@NonNull String content) { - return HtmlUtils.htmlEscape(content).replace("<br/>", "
"); - } - } diff --git a/src/main/java/run/halo/app/service/impl/SheetCommentServiceImpl.java b/src/main/java/run/halo/app/service/impl/SheetCommentServiceImpl.java index 6fd803fe8..ec0acc16f 100644 --- a/src/main/java/run/halo/app/service/impl/SheetCommentServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/SheetCommentServiceImpl.java @@ -1,5 +1,6 @@ package run.halo.app.service.impl; +import org.springframework.stereotype.Service; import run.halo.app.model.entity.SheetComment; import run.halo.app.repository.SheetCommentRepository; import run.halo.app.service.SheetCommentService; @@ -11,6 +12,7 @@ import run.halo.app.service.base.AbstractCrudService; * @author johnniang * @date 19-4-24 */ +@Service public class SheetCommentServiceImpl extends AbstractCrudService implements SheetCommentService { private final SheetCommentRepository sheetCommentRepository; diff --git a/src/main/java/run/halo/app/service/impl/SheetServiceImpl.java b/src/main/java/run/halo/app/service/impl/SheetServiceImpl.java index 7e42b1425..6c8bfdadf 100644 --- a/src/main/java/run/halo/app/service/impl/SheetServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/SheetServiceImpl.java @@ -10,10 +10,12 @@ import run.halo.app.event.post.VisitEvent; import run.halo.app.exception.AlreadyExistsException; import run.halo.app.exception.NotFoundException; import run.halo.app.model.dto.post.SheetDetailDTO; +import run.halo.app.model.dto.post.SheetListDTO; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.Sheet; import run.halo.app.model.enums.PostStatus; import run.halo.app.repository.SheetRepository; +import run.halo.app.service.SheetCommentService; import run.halo.app.service.SheetService; import run.halo.app.service.base.AbstractCrudService; import run.halo.app.utils.DateUtils; @@ -22,6 +24,9 @@ import run.halo.app.utils.ServiceUtils; import java.util.Optional; +import java.util.List; +import java.util.Set; + /** * Sheet service implementation. * @@ -36,9 +41,14 @@ public class SheetServiceImpl extends AbstractCrudService implem public SheetServiceImpl(SheetRepository sheetRepository, ApplicationEventPublisher eventPublisher) { + private final SheetCommentService sheetCommentService; + + public SheetServiceImpl(SheetRepository sheetRepository, + SheetCommentService sheetCommentService) { super(sheetRepository); this.sheetRepository = sheetRepository; this.eventPublisher = eventPublisher; + this.sheetCommentService = sheetCommentService; } @Override @@ -90,6 +100,21 @@ public class SheetServiceImpl extends AbstractCrudService implem return new SheetDetailDTO().convertFrom(sheet); } + @Override + public Page convertToListDto(Page sheetPage) { + Assert.notNull(sheetPage, "Sheet page must not be null"); + + // Get all sheet id + List sheets = sheetPage.getContent(); + + Set sheetIds = ServiceUtils.fetchProperty(sheets, Sheet::getId); + + + return sheetPage.map(sheet -> { + return new SheetListDTO().convertFrom(sheet); + }); + } + @NonNull private Sheet createOrUpdateBy(@NonNull Sheet sheet) { Assert.notNull(sheet, "Sheet must not be null");