Refactor repo, service related comment

pull/146/head
johnniang 2019-04-24 21:39:11 +08:00
parent 511b952b00
commit e77d5449d0
22 changed files with 804 additions and 542 deletions

View File

@ -37,19 +37,22 @@ public class CommentController {
@ApiOperation("Lists comments")
public Page<CommentWithPostVO> pageBy(@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable,
CommentQuery commentQuery) {
return commentService.pageBy(commentQuery, pageable);
Page<Comment> commentPage = commentService.pageBy(commentQuery, pageable);
return commentService.convertToWithPostVo(commentPage);
}
@GetMapping("latest")
@ApiOperation("Pages latest comments")
public List<CommentWithPostVO> pageLatest(@RequestParam(name = "top", defaultValue = "10") int top) {
return commentService.pageLatest(top).getContent();
List<Comment> content = commentService.pageLatest(top).getContent();
return commentService.convertToWithPostVo(content);
}
@GetMapping("status/{status}")
public Page<CommentWithPostVO> pageBy(@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable,
@PathVariable("status") CommentStatus status) {
return commentService.pageBy(status, pageable);
Page<Comment> commentPage = commentService.pageBy(status, pageable);
return commentService.convertToWithPostVo(commentPage);
}
@PostMapping

View File

@ -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<Category> categories = postCategoryService.listCategoryBy(post.getId());
List<Tag> tags = postTagService.listTagsBy(post.getId());
Page<CommentVO> comments = commentService.pageVosBy(post.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort));
Page<BaseCommentVO> 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);

View File

@ -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<CommentVO> listCommentsTree(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
public Page<BaseCommentVO> 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<CommentWithParentVO> listComments(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
public Page<BaseCommentWithParentVO> 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));
}

View File

@ -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<BaseCommentDTO, BaseComment> {
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;
}

View File

@ -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<CommentDTO, Comment> {
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 {
}

View File

@ -0,0 +1,11 @@
package run.halo.app.model.dto;
/**
* Journal dto.
*
* @author johnniang
* @date 19-4-24
*/
public class JournalDTO extends BaseCommentDTO {
}

View File

@ -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;
}

View File

@ -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<BaseCommentVO> children;
}

View File

@ -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;
}
}
}

View File

@ -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<CommentVO> children;

View File

@ -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 {
/**

View File

@ -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<Comment> {
/**
* Finds all comments by post ids.
*
* @param postIds post ids must not be null
* @return a list of comment
*/
@NonNull
List<Comment> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
/**
* Finds all comments by post id.
*
* @param postId post id must not be null
* @return a list of comment
*/
@NonNull
List<Comment> 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<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> 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<Comment> 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<Comment> findAllByPostIdAndStatus(Integer postId, CommentStatus status, Pageable pageable);
}

View File

@ -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<Journal> {
/**
* 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<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
}

View File

@ -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<SheetComment> {
@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<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
}

View File

@ -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<DOMAIN extends BaseComment> extends BaseRepository<DOMAIN, Long>, JpaSpecificationExecutor<DOMAIN> {
@NoRepositoryBean
public interface BaseCommentRepository<COMMENT extends BaseComment> extends BaseRepository<COMMENT, Long>, JpaSpecificationExecutor<COMMENT> {
/**
* Finds all comments by status.
@ -24,7 +29,55 @@ public interface BaseCommentRepository<DOMAIN extends BaseComment> extends BaseR
* @return a page of comment
*/
@NonNull
Page<DOMAIN> findAllByStatus(@Nullable CommentStatus status, @NonNull Pageable pageable);
Page<COMMENT> 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<COMMENT> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
/**
* Finds all comments by post id.
*
* @param postId post id must not be null
* @return a list of comment
*/
@NonNull
List<COMMENT> 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<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> 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<COMMENT> 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<COMMENT> findAllByPostIdAndStatus(Integer postId, CommentStatus status, Pageable pageable);
}

View File

@ -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<Comment, Long> {
/**
* %d: parent commentator id
* %s: parent commentator author name
* %s: comment content
*/
String COMMENT_TEMPLATE = "<a href='#comment-id-%d'>@%s</a> %s";
/**
* Lists latest comments.
*
* @param top top number must not be less than 0
* @return a page of comments
*/
@NonNull
Page<CommentWithPostVO> 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<CommentWithPostVO> 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<CommentWithPostVO> 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<Comment> 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<Integer, Long> countByPostIds(@Nullable Collection<Integer> postIds);
public interface CommentService extends BaseCommentService<Comment> {
/**
* Creates a comment by comment param.
@ -88,32 +27,20 @@ public interface CommentService extends CrudService<Comment, Long> {
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<CommentVO> pageVosBy(@NonNull Integer postId, @NonNull Pageable pageable);
Page<CommentWithPostVO> convertToWithPostVo(@NonNull Page<Comment> 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<CommentWithParentVO> 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<CommentWithPostVO> convertToWithPostVo(@Nullable List<Comment> comments);
}

View File

@ -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<Sheet, Integer> {
*/
@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<SheetListDTO> convertToListDto(@NonNull Page<Sheet> sheetPage);
}

View File

@ -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<COMMENT extends BaseComment> extends CrudService<COMMENT, Long> {
/**
* %d: parent commentator id
* %s: parent commentator author name
* %s: comment content
*/
@Deprecated
String COMMENT_TEMPLATE = "<a href='#comment-id-%d'>@%s</a> %s";
/**
* Lists comments by post id.
*
* @param postId post id must not be null
* @return a list of comment
*/
@NonNull
List<COMMENT> listBy(@NonNull Integer postId);
/**
* Lists latest comments.
*
* @param top top number must not be less than 0
* @return a page of comments
*/
@NonNull
Page<COMMENT> 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<COMMENT> 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<COMMENT> 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<BaseCommentVO> 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<BaseCommentWithParentVO> 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<Integer, Long> countByPostIds(@Nullable Collection<Integer> 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);
}

View File

@ -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<COMMENT extends BaseComment> extends AbstractCrudService<COMMENT, Long> implements BaseCommentService<COMMENT> {
private final BaseCommentRepository<COMMENT> baseCommentRepository;
protected final PostRepository postRepository;
protected final OptionService optionService;
protected final ApplicationEventPublisher eventPublisher;
public BaseCommentServiceImpl(BaseCommentRepository<COMMENT> baseCommentRepository,
PostRepository postRepository,
OptionService optionService,
ApplicationEventPublisher eventPublisher) {
super(baseCommentRepository);
this.baseCommentRepository = baseCommentRepository;
this.postRepository = postRepository;
this.optionService = optionService;
this.eventPublisher = eventPublisher;
}
@Override
public List<COMMENT> listBy(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
return baseCommentRepository.findAllByPostId(postId);
}
@Override
public Page<COMMENT> 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<COMMENT> 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<COMMENT> pageBy(CommentQuery commentQuery, Pageable pageable) {
Assert.notNull(pageable, "Page info must not be null");
return baseCommentRepository.findAll(buildSpecByQuery(commentQuery), pageable);
}
@Override
public Page<BaseCommentVO> 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<COMMENT> comments = baseCommentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED);
// Init the top virtual comment
BaseCommentVO topVirtualComment = new BaseCommentVO();
topVirtualComment.setId(0L);
topVirtualComment.setChildren(new LinkedList<>());
Comparator<BaseCommentVO> commentVOComparator = buildCommentComparator(pageable.getSortOr(Sort.by(Sort.Direction.DESC, "createTime")));
// Concrete the comment tree
concreteTree(topVirtualComment, new LinkedList<>(comments), commentVOComparator);
List<BaseCommentVO> topComments = topVirtualComment.getChildren();
List<BaseCommentVO> 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<BaseCommentWithParentVO> 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<COMMENT> commentPage = baseCommentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED, pageable);
// Get all comments
List<COMMENT> comments = commentPage.getContent();
// Get all comment parent ids
Set<Long> parentIds = ServiceUtils.fetchProperty(comments, COMMENT::getParentId);
// Get all parent comments
List<COMMENT> parentComments = baseCommentRepository.findAllByIdIn(parentIds, pageable.getSort());
// Convert to comment map (Key: comment id, value: comment)
Map<Long, COMMENT> parentCommentMap = ServiceUtils.convertToMap(parentComments, COMMENT::getId);
Map<Long, BaseCommentWithParentVO> 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<Integer, Long> countByPostIds(Collection<Integer> postIds) {
if (CollectionUtils.isEmpty(postIds)) {
return Collections.emptyMap();
}
// Get all comment counts
List<CommentCountProjection> 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<COMMENT> buildSpecByQuery(@NonNull CommentQuery commentQuery) {
Assert.notNull(commentQuery, "Comment query must not be null");
return (Specification<COMMENT>) (root, query, criteriaBuilder) -> {
List<Predicate> 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<BaseCommentVO> 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<COMMENT> comments,
@NonNull Comparator<BaseCommentVO> 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<COMMENT> 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);
}
}
}

View File

@ -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<Comment, Long> implements CommentService {
public class CommentServiceImpl extends BaseCommentServiceImpl<Comment> 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<CommentWithPostVO> 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<CommentWithPostVO> 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<Comment> commentPage = commentRepository.findAllByStatus(status, pageable);
return convertBy(commentPage);
}
@Override
public Page<CommentWithPostVO> pageBy(CommentQuery commentQuery, Pageable pageable) {
Assert.notNull(commentQuery, "Comment query must not be null");
Assert.notNull(pageable, "Page info must not be null");
Page<Comment> commentPage = commentRepository.findAll(buildSpecByQuery(commentQuery), pageable);
return convertBy(commentPage);
}
@NonNull
private Specification<Comment> buildSpecByQuery(@NonNull CommentQuery commentQuery) {
Assert.notNull(commentQuery, "Comment query must not be null");
return (Specification<Comment>) (root, query, criteriaBuilder) -> {
List<Predicate> 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<Comment> listBy(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
return commentRepository.findAllByPostId(postId);
}
@Override
public Map<Integer, Long> countByPostIds(Collection<Integer> postIds) {
if (CollectionUtils.isEmpty(postIds)) {
return Collections.emptyMap();
}
// Get all comment counts
List<CommentCountProjection> commentCountProjections = commentRepository.countByPostIds(postIds);
return ServiceUtils.convertToMap(commentCountProjections, CommentCountProjection::getPostId, CommentCountProjection::getCount);
}
@Override
@ -167,264 +68,20 @@ public class CommentServiceImpl extends AbstractCrudService<Comment, Long> 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<CommentVO> 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<Comment> 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<CommentVO> topComments = topVirtualComment.getChildren();
List<CommentVO> 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<CommentWithParentVO> 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<Comment> commentPage = commentRepository.findAllByPostIdAndStatus(postId, CommentStatus.PUBLISHED, pageable);
// Get all comments
List<Comment> comments = commentPage.getContent();
// Get all comment parent ids
Set<Long> parentIds = ServiceUtils.fetchProperty(comments, Comment::getParentId);
// Get all parent comments
List<Comment> parentComments = commentRepository.findAllByIdIn(parentIds, pageable.getSort());
// Convert to comment map (Key: comment id, value: comment)
Map<Long, Comment> parentCommentMap = ServiceUtils.convertToMap(parentComments, Comment::getId);
Map<Long, CommentWithParentVO> 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<CommentVO> 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<Comment> comments, @NonNull Comparator<CommentVO> 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<Comment> 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<CommentWithPostVO> convertBy(@NonNull Page<Comment> commentPage) {
public Page<CommentWithPostVO> convertToWithPostVo(Page<Comment> 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<CommentWithPostVO> convertBy(@Nullable List<Comment> comments) {
@Override
public List<CommentWithPostVO> convertToWithPostVo(List<Comment> comments) {
if (CollectionUtils.isEmpty(comments)) {
return Collections.emptyList();
}
@ -446,8 +103,4 @@ public class CommentServiceImpl extends AbstractCrudService<Comment, Long> imple
}).collect(Collectors.toList());
}
private String formatContent(@NonNull String content) {
return HtmlUtils.htmlEscape(content).replace("&lt;br/&gt;", "<br/>");
}
}

View File

@ -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<SheetComment, Long> implements SheetCommentService {
private final SheetCommentRepository sheetCommentRepository;

View File

@ -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<Sheet, Integer> 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<Sheet, Integer> implem
return new SheetDetailDTO().convertFrom(sheet);
}
@Override
public Page<SheetListDTO> convertToListDto(Page<Sheet> sheetPage) {
Assert.notNull(sheetPage, "Sheet page must not be null");
// Get all sheet id
List<Sheet> sheets = sheetPage.getContent();
Set<Integer> 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");