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 cc085505a..c15084c88 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 @@ -5,7 +5,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.*; -import run.halo.app.model.dto.CommentDTO; +import run.halo.app.model.dto.BaseCommentDTO; import run.halo.app.model.entity.Comment; import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.params.CommentParam; @@ -57,29 +57,26 @@ public class CommentController { @PostMapping @ApiOperation("Creates a comment (new or reply)") - public CommentDTO createBy(@RequestBody CommentParam commentParam) { - return new CommentDTO().convertFrom(commentService.createBy(commentParam)); + public BaseCommentDTO createBy(@RequestBody CommentParam commentParam) { + Comment createdComment = commentService.createBy(commentParam); + return commentService.convertTo(createdComment); } @PutMapping("{commentId:\\d+}/status/{status}") @ApiOperation("Updates comment status") - public CommentDTO updateStatusBy(@PathVariable("commentId") Long commentId, - @PathVariable("status") CommentStatus status) { + public BaseCommentDTO updateStatusBy(@PathVariable("commentId") Long commentId, + @PathVariable("status") CommentStatus status) { // Update comment status Comment updatedComment = commentService.updateStatus(commentId, status); - return new CommentDTO().convertFrom(updatedComment); + return commentService.convertTo(updatedComment); } @DeleteMapping("{commentId:\\d+}") @ApiOperation("Deletes comment permanently and recursively") - public CommentDTO deleteBy(@PathVariable("commentId") Long commentId) { - // Get comment by id - Comment comment = commentService.getById(commentId); + public BaseCommentDTO deleteBy(@PathVariable("commentId") Long commentId) { + Comment deletedComment = commentService.removeById(commentId); - // Remove it - commentService.remove(comment); - - return new CommentDTO().convertFrom(comment); + return commentService.convertTo(deletedComment); } } diff --git a/src/main/java/run/halo/app/controller/admin/api/JournalController.java b/src/main/java/run/halo/app/controller/admin/api/JournalController.java new file mode 100644 index 000000000..4162b6cf5 --- /dev/null +++ b/src/main/java/run/halo/app/controller/admin/api/JournalController.java @@ -0,0 +1,51 @@ +package run.halo.app.controller.admin.api; + +import io.swagger.annotations.ApiOperation; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.*; +import run.halo.app.model.dto.BaseCommentDTO; +import run.halo.app.model.entity.Journal; +import run.halo.app.model.params.JournalParam; +import run.halo.app.service.JournalService; + +import java.util.List; + +/** + * Journal controller. + * + * @author johnniang + * @date 19-4-25 + */ +@RestController +@RequestMapping("/api/admin/journals") +public class JournalController { + + private final JournalService journalService; + + public JournalController(JournalService journalService) { + this.journalService = journalService; + } + + @GetMapping + @ApiOperation("Gets latest journals") + public Page pageBy(Pageable pageable) { + Page journalPage = journalService.pageBy(pageable); + return journalService.convertTo(journalPage); + } + + @GetMapping("latest") + @ApiOperation("Gets latest journals") + public List pageLatest(@RequestParam(name = "top", defaultValue = "10") int top) { + List journals = journalService.pageLatest(top).getContent(); + return journalService.convertTo(journals); + } + + @PostMapping + @ApiOperation("Creates a journal") + public BaseCommentDTO createBy(@RequestBody JournalParam journalParam) { + Journal createdJournal = journalService.createBy(journalParam); + return journalService.convertTo(createdJournal); + } + +} 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 5146e29ef..e487c0978 100644 --- a/src/main/java/run/halo/app/model/dto/CommentDTO.java +++ b/src/main/java/run/halo/app/model/dto/CommentDTO.java @@ -10,8 +10,8 @@ import lombok.ToString; * @author johnniang */ @Data -@ToString -@EqualsAndHashCode +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) public class CommentDTO extends BaseCommentDTO { } diff --git a/src/main/java/run/halo/app/model/params/JournalParam.java b/src/main/java/run/halo/app/model/params/JournalParam.java new file mode 100644 index 000000000..e9899cc33 --- /dev/null +++ b/src/main/java/run/halo/app/model/params/JournalParam.java @@ -0,0 +1,39 @@ +package run.halo.app.model.params; + +import lombok.Data; +import run.halo.app.model.dto.base.InputConverter; +import run.halo.app.model.entity.Journal; + +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * Journal param. + * + * @author johnniang + * @date 19-4-25 + */ +@Data +public class JournalParam implements InputConverter { + + @NotBlank(message = "Author name must not be blank") + @Size(max = 50, message = "Length of comment author name must not be more than {max}") + private String author; + + @NotBlank(message = "Email must not be blank") + @Email(message = "Email's format is incorrect") + @Size(max = 255, message = "Length of comment email must not be more than {max}") + private String email; + + @Size(max = 127, message = "Length of comment author url must not be more than {max}") + private String authorUrl; + + @NotBlank(message = "Content must not be blank") + @Size(max = 511, message = "Length of comment content must not be more than {max}") + private String content; + + @Min(value = 0, message = "Parent id must not be less than {value}") + private Long parentId = 0L; +} diff --git a/src/main/java/run/halo/app/model/properties/PropertyEnum.java b/src/main/java/run/halo/app/model/properties/PropertyEnum.java index ac8e2895f..7456d4749 100644 --- a/src/main/java/run/halo/app/model/properties/PropertyEnum.java +++ b/src/main/java/run/halo/app/model/properties/PropertyEnum.java @@ -1,6 +1,5 @@ package run.halo.app.model.properties; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; diff --git a/src/main/java/run/halo/app/repository/JournalRepository.java b/src/main/java/run/halo/app/repository/JournalRepository.java index f774bbfe8..947a1b1a2 100644 --- a/src/main/java/run/halo/app/repository/JournalRepository.java +++ b/src/main/java/run/halo/app/repository/JournalRepository.java @@ -1,5 +1,7 @@ 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.Journal; @@ -25,4 +27,13 @@ public interface JournalRepository extends BaseCommentRepository { @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); + + /** + * Finds all journals by parent id. + * + * @param parentId parent id must not be null + * @param pageable page info must not be null + * @return a page of journal + */ + Page findAllByParentId(@NonNull Long parentId, @NonNull Pageable pageable); } diff --git a/src/main/java/run/halo/app/service/JournalService.java b/src/main/java/run/halo/app/service/JournalService.java index d5a481bc5..b7efc5f4f 100644 --- a/src/main/java/run/halo/app/service/JournalService.java +++ b/src/main/java/run/halo/app/service/JournalService.java @@ -1,7 +1,11 @@ package run.halo.app.service; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.lang.NonNull; import run.halo.app.model.entity.Journal; -import run.halo.app.service.base.CrudService; +import run.halo.app.model.params.JournalParam; +import run.halo.app.service.base.BaseCommentService; /** * Journal service interface. @@ -9,6 +13,22 @@ import run.halo.app.service.base.CrudService; * @author johnniang * @date 19-4-24 */ -public interface JournalService extends CrudService { +public interface JournalService extends BaseCommentService { + /** + * Creates a journal. + * + * @param journalParam journal param must not be null + * @return created journal + */ + @NonNull + Journal createBy(@NonNull JournalParam journalParam); + + /** + * Gets a page of journal + * + * @param pageable page info must not be null + * @return a page of journal + */ + Page pageBy(@NonNull Pageable pageable); } diff --git a/src/main/java/run/halo/app/service/base/BaseCommentService.java b/src/main/java/run/halo/app/service/base/BaseCommentService.java index 804379bf6..3bf72de87 100644 --- a/src/main/java/run/halo/app/service/base/BaseCommentService.java +++ b/src/main/java/run/halo/app/service/base/BaseCommentService.java @@ -4,6 +4,7 @@ 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.dto.BaseCommentDTO; import run.halo.app.model.entity.BaseComment; import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.params.CommentQuery; @@ -13,7 +14,6 @@ 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. @@ -115,4 +115,31 @@ public interface BaseCommentService extends CrudSer */ @NonNull COMMENT updateStatus(@NonNull Long commentId, @NonNull CommentStatus status); + + /** + * Converts to base comment dto. + * + * @param comment comment must not be null + * @return base comment dto + */ + @NonNull + BaseCommentDTO convertTo(@NonNull COMMENT comment); + + /** + * Converts to base comment dto list. + * + * @param comments comment list must not be null + * @return a list of base comment dto + */ + @NonNull + List convertTo(@NonNull List comments); + + /** + * Converts to base comment dto page. + * + * @param commentPage comment page must not be null + * @return a page of base comment dto + */ + @NonNull + Page convertTo(@NonNull Page commentPage); } diff --git a/src/main/java/run/halo/app/service/impl/BaseCommentServiceImpl.java b/src/main/java/run/halo/app/service/impl/BaseCommentServiceImpl.java index e262a2af4..e2f40c5d2 100644 --- a/src/main/java/run/halo/app/service/impl/BaseCommentServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/BaseCommentServiceImpl.java @@ -18,6 +18,7 @@ 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.BaseCommentDTO; import run.halo.app.model.entity.BaseComment; import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.params.CommentQuery; @@ -38,6 +39,7 @@ import run.halo.app.utils.ServletUtils; import javax.persistence.criteria.Predicate; import java.util.*; +import java.util.stream.Collectors; /** * Base comment service implementation. @@ -76,12 +78,7 @@ public abstract class BaseCommentServiceImpl extend @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); + return listAll(buildLatestPageable(top)); } @Override @@ -281,8 +278,32 @@ public abstract class BaseCommentServiceImpl extend return updatedComment; } + @Override + public List convertTo(List comments) { + if (CollectionUtils.isEmpty(comments)) { + return Collections.emptyList(); + } + return comments.stream() + .map(this::convertTo) + .collect(Collectors.toList()); + } + + @Override + public Page convertTo(Page commentPage) { + Assert.notNull(commentPage, "Comment page must not be null"); + + return commentPage.map(this::convertTo); + } + + @Override + public BaseCommentDTO convertTo(COMMENT comment) { + Assert.notNull(comment, "Comment must not be null"); + + return new BaseCommentDTO().convertFrom(comment); + } + @NonNull - private Specification buildSpecByQuery(@NonNull CommentQuery commentQuery) { + protected Specification buildSpecByQuery(@NonNull CommentQuery commentQuery) { Assert.notNull(commentQuery, "Comment query must not be null"); return (Specification) (root, query, criteriaBuilder) -> { @@ -313,7 +334,7 @@ public abstract class BaseCommentServiceImpl extend * @param sort sort info * @return comment comparator */ - private Comparator buildCommentComparator(Sort sort) { + protected 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"); @@ -339,9 +360,9 @@ public abstract class BaseCommentServiceImpl extend * @param comments comment list must not null * @param commentComparator comment vo comparator */ - private void concreteTree(@NonNull BaseCommentVO parentComment, - @Nullable Collection comments, - @NonNull Comparator commentComparator) { + protected 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"); @@ -384,4 +405,17 @@ public abstract class BaseCommentServiceImpl extend parentComment.getChildren().sort(commentComparator); } } + + /** + * Builds latest page request. + * + * @param top top must not be less than 1 + * @return latest page request + */ + @NonNull + Pageable buildLatestPageable(int top) { + Assert.isTrue(top > 0, "Top number must not be less than 0"); + + return PageRequest.of(0, top, Sort.by(Sort.Direction.DESC, "createTime")); + } } 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 a9bfc0a23..9849800aa 100644 --- a/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/CommentServiceImpl.java @@ -59,7 +59,7 @@ public class CommentServiceImpl extends BaseCommentServiceImpl implemen if (authentication != null) { User user = authentication.getDetail().getUser(); - commentParam.setAuthor(StringUtils.isEmpty(user.getNickname()) ? user.getUsername() : user.getNickname()); + commentParam.setAuthor(StringUtils.isBlank(user.getNickname()) ? user.getUsername() : user.getNickname()); commentParam.setEmail(user.getEmail()); commentParam.setAuthorUrl(optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL)); } diff --git a/src/main/java/run/halo/app/service/impl/JournalServiceImpl.java b/src/main/java/run/halo/app/service/impl/JournalServiceImpl.java index c403d421b..f4b564dc0 100644 --- a/src/main/java/run/halo/app/service/impl/JournalServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/JournalServiceImpl.java @@ -1,9 +1,22 @@ package run.halo.app.service.impl; +import cn.hutool.core.lang.Assert; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; import run.halo.app.model.entity.Journal; +import run.halo.app.model.entity.User; +import run.halo.app.model.params.JournalParam; +import run.halo.app.model.properties.BlogProperties; import run.halo.app.repository.JournalRepository; +import run.halo.app.repository.PostRepository; +import run.halo.app.security.authentication.Authentication; +import run.halo.app.security.context.SecurityContextHolder; import run.halo.app.service.JournalService; -import run.halo.app.service.base.AbstractCrudService; +import run.halo.app.service.OptionService; +import run.halo.app.utils.ValidationUtils; /** * Journal service implementation. @@ -11,12 +24,52 @@ import run.halo.app.service.base.AbstractCrudService; * @author johnniang * @date 19-4-24 */ -public class JournalServiceImpl extends AbstractCrudService implements JournalService { +@Service +public class JournalServiceImpl extends BaseCommentServiceImpl implements JournalService { private final JournalRepository journalRepository; - public JournalServiceImpl(JournalRepository journalRepository) { - super(journalRepository); + public JournalServiceImpl(JournalRepository journalRepository, + PostRepository postRepository, + OptionService optionService, + ApplicationEventPublisher eventPublisher) { + super(journalRepository, postRepository, optionService, eventPublisher); this.journalRepository = journalRepository; } + + @Override + public Journal createBy(JournalParam journalParam) { + Assert.notNull(journalParam, "Journal param must not be null"); + + // Check user login status + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null) { + // Get user detail + User user = authentication.getDetail().getUser(); + // Set some default value + journalParam.setAuthor(StringUtils.isBlank(user.getNickname()) ? user.getUsername() : user.getNickname()); + journalParam.setAuthorUrl(optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL)); + journalParam.setEmail(user.getEmail()); + } + + // Validate the journal param + ValidationUtils.validate(journalParam); + + // Convert, create and return + return createBy(journalParam.convertTo()); + } + + @Override + public Page pageBy(Pageable pageable) { + Assert.notNull(pageable, "Page info must not be null"); + + return journalRepository.findAllByParentId(0L, pageable); + } + + @Override + public Page pageLatest(int top) { + return pageBy(buildLatestPageable(top)); + } + } diff --git a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java index 5814ae751..2340bb47c 100644 --- a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java @@ -130,7 +130,7 @@ public class OptionServiceImpl extends AbstractCrudService impl Set keys = ServiceUtils.fetchProperty(options, Option::getKey); - Map result = ServiceUtils.convertToMap(options, Option::getKey, option -> { + Map userDefinedOptionMap = ServiceUtils.convertToMap(options, Option::getKey, option -> { String key = option.getKey(); PropertyEnum propertyEnum = propertyEnumMap.get(key); @@ -142,6 +142,8 @@ public class OptionServiceImpl extends AbstractCrudService impl return PropertyEnum.convertTo(option.getValue(), propertyEnum); }); + Map result = new HashMap<>(userDefinedOptionMap); + // Add default property propertyEnumMap.keySet() .stream()