* Update FUNDING.yml

* merge from master

* feat: update page default sort && update the pre and next of posts

* feat: adapter dev branch

* Feat: update getAdjacentPosts return && update post ftl

* fix: revert gradle-wrapper.jar

Co-authored-by: Ryan Wang <i@ryanc.cc>
Co-authored-by: Jiahuan Shen <shenjiahuan1999@hotmail.com>
Co-authored-by: John Niang <johnniang@riseup.net>
Co-authored-by: weiwensangsang <weiwensangsang@users.noreply.github.com>
Co-authored-by: Lei XinXin <40338580+NGLSL@users.noreply.github.com>
Co-authored-by: 寒山 <ms915818993@163.com>
Co-authored-by: IJKZEN <ijkzen@outlook.com>
pull/503/head
leozhou 2020-01-16 18:00:33 +08:00 committed by Ryan Wang
parent f4c2ca2f8d
commit 89086dd345
9 changed files with 264 additions and 76 deletions

2
.github/FUNDING.yml vendored
View File

@ -5,4 +5,4 @@ patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: https://pay.ryanc.cc
custom: ['https://pay.ryanc.cc']

View File

@ -1,6 +1,8 @@
package run.halo.app.controller.content;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.PageUtil;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

View File

@ -64,7 +64,7 @@ public class ContentIndexController {
* Render blog index
*
* @param model model
* @param page current page number
* @param page current page number
* @return template path: themes/{theme}/index.ftl
*/
@GetMapping(value = "page/{page}")

View File

@ -1,11 +1,11 @@
package run.halo.app.controller.content.model;
import cn.hutool.core.util.PageUtil;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
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.stereotype.Component;
import org.springframework.ui.Model;
import run.halo.app.cache.StringCacheStore;
@ -15,16 +15,14 @@ import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostMeta;
import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.properties.PostProperties;
import run.halo.app.model.support.HaloConst;
import run.halo.app.model.vo.AdjacentPostVO;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.*;
import run.halo.app.utils.MarkdownUtils;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Post Model
*
@ -53,14 +51,14 @@ public class PostModel {
private final StringCacheStore cacheStore;
public PostModel(PostService postService,
ThemeService themeService,
PostCategoryService postCategoryService,
CategoryService categoryService,
PostMetaService postMetaService,
PostTagService postTagService,
TagService tagService,
OptionService optionService,
StringCacheStore cacheStore) {
ThemeService themeService,
PostCategoryService postCategoryService,
CategoryService categoryService,
PostMetaService postMetaService,
PostTagService postTagService,
TagService tagService,
OptionService optionService,
StringCacheStore cacheStore) {
this.postService = postService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
@ -75,21 +73,26 @@ public class PostModel {
public String content(Post post, String token, Model model) {
if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) {
String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl());
String redirect = String
.format("%s/archives/%s/password", optionService.getBlogBaseUrl(),
post.getUrl());
return "redirect:" + redirect;
}
if (!StringUtils.isEmpty(token)) {
// verify token
String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限"));
String cachedToken = cacheStore.getAny(token, String.class)
.orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该文章的访问权限");
}
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
}
postService.publishVisitEvent(post.getId());
postService.getNextPost(post.getCreateTime()).ifPresent(nextPost -> model.addAttribute("nextPost", nextPost));
postService.getPrePost(post.getCreateTime()).ifPresent(prePost -> model.addAttribute("prePost", prePost));
AdjacentPostVO adjacentPostVO = postService.getAdjacentPosts(post);
adjacentPostVO.getOptionalPrePost().ifPresent(prePost -> model.addAttribute("prePost", prePost));
adjacentPostVO.getOptionalNextPost().ifPresent(nextPost -> model.addAttribute("nextPost", nextPost));
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
List<Tag> tags = postTagService.listTagsBy(post.getId());
@ -104,7 +107,8 @@ public class PostModel {
// TODO,Will be deprecated
model.addAttribute("comments", Page.empty());
if (themeService.templateExists(ThemeService.CUSTOM_POST_PREFIX + post.getTemplate() + HaloConst.SUFFIX_FTL)) {
if (themeService.templateExists(
ThemeService.CUSTOM_POST_PREFIX + post.getTemplate() + HaloConst.SUFFIX_FTL)) {
return themeService.render(ThemeService.CUSTOM_POST_PREFIX + post.getTemplate());
}
@ -112,9 +116,9 @@ public class PostModel {
}
public String list(Integer page, Model model, String decide, String template) {
String indexSort = optionService.getByPropertyOfNonNull(PostProperties.INDEX_SORT).toString();
int pageSize = optionService.getPostPageSize();
Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort)));
Pageable pageable = PageRequest
.of(page >= 1 ? page - 1 : page, pageSize, postService.getPostDefaultSort());
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);

View File

@ -0,0 +1,33 @@
package run.halo.app.model.vo;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import run.halo.app.model.entity.Post;
/**
* AdjacentPost class
*
* @author zhouchunjie
* @date 2020/1/12
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AdjacentPostVO {
private Post prePost;
private Post nextPost;
public Optional<Post> getOptionalPrePost(){
return Optional.ofNullable(this.getPrePost());
}
public Optional<Post> getOptionalNextPost() {
return Optional.ofNullable(this.getNextPost());
}
}

View File

@ -1,5 +1,8 @@
package run.halo.app.repository.base;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@ -10,10 +13,6 @@ import org.springframework.lang.NonNull;
import run.halo.app.model.entity.BasePost;
import run.halo.app.model.enums.PostStatus;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* Base post repository.
*

View File

@ -1,12 +1,15 @@
package run.halo.app.service;
import javax.validation.constraints.NotNull;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostMeta;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.params.PostQuery;
import run.halo.app.model.vo.AdjacentPostVO;
import run.halo.app.model.vo.ArchiveMonthVO;
import run.halo.app.model.vo.ArchiveYearVO;
import run.halo.app.model.vo.PostDetailVO;
@ -228,4 +231,21 @@ public interface PostService extends BasePostService<Post> {
* @param postId postId must not be null
*/
void publishVisitEvent(@NonNull Integer postId);
/**
* Gets pre && next post.
* @param currentPost post must not be null
* @return AdjacentPostVO. it contains prePost and nextPost.
* AdjacentPostVO will not be null. But prePost and nextPost may be null.
*/
@NotNull
AdjacentPostVO getAdjacentPosts(Post currentPost);
/**
* Get Post Pageable default sort
* @Desc contains three parts. First, Top Priority; Second, From Custom index sort; Third, basic id sort
* @return
*/
@NotNull
Sort getPostDefaultSort();
}

View File

@ -1,12 +1,32 @@
package run.halo.app.service.impl;
import static org.springframework.data.domain.Sort.Direction.DESC;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.StrUtil;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
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;
@ -20,31 +40,39 @@ import run.halo.app.event.logger.LogEvent;
import run.halo.app.event.post.PostVisitEvent;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.dto.BaseMetaDTO;
import run.halo.app.model.entity.*;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostCategory;
import run.halo.app.model.entity.PostComment;
import run.halo.app.model.entity.PostMeta;
import run.halo.app.model.entity.PostTag;
import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.LogType;
import run.halo.app.model.enums.PostPermalinkType;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.params.PostQuery;
import run.halo.app.model.properties.PermalinkProperties;
import run.halo.app.model.properties.PostProperties;
import run.halo.app.model.vo.AdjacentPostVO;
import run.halo.app.model.vo.ArchiveMonthVO;
import run.halo.app.model.vo.ArchiveYearVO;
import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.repository.PostRepository;
import run.halo.app.service.*;
import run.halo.app.service.CategoryService;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostCommentService;
import run.halo.app.service.PostMetaService;
import run.halo.app.service.PostService;
import run.halo.app.service.PostTagService;
import run.halo.app.service.TagService;
import run.halo.app.utils.DateUtils;
import run.halo.app.utils.MarkdownUtils;
import run.halo.app.utils.ServiceUtils;
import run.halo.app.utils.SlugUtils;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Post service implementation.
*
@ -77,14 +105,14 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
private final OptionService optionService;
public PostServiceImpl(PostRepository postRepository,
TagService tagService,
CategoryService categoryService,
PostTagService postTagService,
PostCategoryService postCategoryService,
PostCommentService postCommentService,
ApplicationEventPublisher eventPublisher,
PostMetaService postMetaService,
OptionService optionService) {
TagService tagService,
CategoryService categoryService,
PostTagService postTagService,
PostCategoryService postCategoryService,
PostCommentService postCommentService,
ApplicationEventPublisher eventPublisher,
PostMetaService postMetaService,
OptionService optionService) {
super(postRepository, optionService);
this.postRepository = postRepository;
this.tagService = tagService;
@ -121,22 +149,26 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
@Override
@Transactional
public PostDetailVO createBy(Post postToCreate, Set<Integer> tagIds, Set<Integer> categoryIds, Set<PostMeta> postMetas, boolean autoSave) {
public PostDetailVO createBy(Post postToCreate, Set<Integer> tagIds, Set<Integer> categoryIds,
Set<PostMeta> postMetas, boolean autoSave) {
PostDetailVO createdPost = createOrUpdate(postToCreate, tagIds, categoryIds, postMetas);
if (!autoSave) {
// Log the creation
LogEvent logEvent = new LogEvent(this, createdPost.getId().toString(), LogType.POST_PUBLISHED, createdPost.getTitle());
LogEvent logEvent = new LogEvent(this, createdPost.getId().toString(),
LogType.POST_PUBLISHED, createdPost.getTitle());
eventPublisher.publishEvent(logEvent);
}
return createdPost;
}
@Override
public PostDetailVO createBy(Post postToCreate, Set<Integer> tagIds, Set<Integer> categoryIds, boolean autoSave) {
public PostDetailVO createBy(Post postToCreate, Set<Integer> tagIds, Set<Integer> categoryIds,
boolean autoSave) {
PostDetailVO createdPost = createOrUpdate(postToCreate, tagIds, categoryIds, null);
if (!autoSave) {
// Log the creation
LogEvent logEvent = new LogEvent(this, createdPost.getId().toString(), LogType.POST_PUBLISHED, createdPost.getTitle());
LogEvent logEvent = new LogEvent(this, createdPost.getId().toString(),
LogType.POST_PUBLISHED, createdPost.getTitle());
eventPublisher.publishEvent(logEvent);
}
return createdPost;
@ -144,13 +176,15 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
@Override
@Transactional
public PostDetailVO updateBy(Post postToUpdate, Set<Integer> tagIds, Set<Integer> categoryIds, Set<PostMeta> postMetas, boolean autoSave) {
public PostDetailVO updateBy(Post postToUpdate, Set<Integer> tagIds, Set<Integer> categoryIds,
Set<PostMeta> postMetas, boolean autoSave) {
// Set edit time
postToUpdate.setEditTime(DateUtils.now());
PostDetailVO updatedPost = createOrUpdate(postToUpdate, tagIds, categoryIds, postMetas);
if (!autoSave) {
// Log the creation
LogEvent logEvent = new LogEvent(this, updatedPost.getId().toString(), LogType.POST_EDITED, updatedPost.getTitle());
LogEvent logEvent = new LogEvent(this, updatedPost.getId().toString(),
LogType.POST_EDITED, updatedPost.getTitle());
eventPublisher.publishEvent(logEvent);
}
return updatedPost;
@ -169,7 +203,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Optional<Post> postOptional = postRepository.findBy(year, month, url);
return postOptional.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
return postOptional
.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
}
@Override
@ -181,7 +216,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Optional<Post> postOptional = postRepository.findBy(year, month, url, status);
return postOptional.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
return postOptional
.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
}
@Override
@ -193,7 +229,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Optional<Post> postOptional = postRepository.findBy(year, month, day, url);
return postOptional.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
return postOptional
.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
}
@Override
@ -206,7 +243,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Optional<Post> postOptional = postRepository.findBy(year, month, day, url, status);
return postOptional.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
return postOptional
.orElseThrow(() -> new NotFoundException("查询不到该文章的信息").setErrorData(url));
}
@Override
@ -225,7 +263,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
@Override
public List<ArchiveYearVO> listYearArchives() {
// Get all posts
List<Post> posts = postRepository.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
List<Post> posts = postRepository
.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
Map<Integer, List<Post>> yearPostMap = new HashMap<>(8);
@ -235,7 +274,6 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
.add(post);
});
List<ArchiveYearVO> archives = new LinkedList<>();
yearPostMap.forEach((year, postList) -> {
@ -257,7 +295,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
@Override
public List<ArchiveMonthVO> listMonthArchives() {
// Get all posts
List<Post> posts = postRepository.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
List<Post> posts = postRepository
.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
Map<Integer, Map<Integer, List<Post>>> yearMonthPostMap = new HashMap<>(8);
@ -265,7 +304,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Calendar calendar = DateUtils.convertTo(post.getCreateTime());
yearMonthPostMap.computeIfAbsent(calendar.get(Calendar.YEAR), year -> new HashMap<>())
.computeIfAbsent((calendar.get(Calendar.MONTH) + 1), month -> new LinkedList<>())
.computeIfAbsent((calendar.get(Calendar.MONTH) + 1),
month -> new LinkedList<>())
.add(post);
});
@ -384,7 +424,6 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
public String exportMarkdown(Post post) {
Assert.notNull(post, "Post must not be null");
StrBuilder content = new StrBuilder("---\n");
content.append("type: ").append("post").append("\n");
@ -419,7 +458,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
if (postMetas.size() > 0) {
content.append("postMetas:").append("\n");
for (PostMeta postMeta : postMetas) {
content.append(" - ").append(postMeta.getKey()).append(" : ").append(postMeta.getValue()).append("\n");
content.append(" - ").append(postMeta.getKey()).append(" : ")
.append(postMeta.getValue()).append("\n");
}
}
@ -467,7 +507,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Post deletedPost = super.removeById(postId);
// Log it
eventPublisher.publishEvent(new LogEvent(this, postId.toString(), LogType.POST_DELETED, deletedPost.getTitle()));
eventPublisher.publishEvent(new LogEvent(this, postId.toString(), LogType.POST_DELETED,
deletedPost.getTitle()));
return deletedPost;
}
@ -484,7 +525,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
// Get category list map
Map<Integer, List<Category>> categoryListMap = postCategoryService.listCategoryListMap(postIds);
Map<Integer, List<Category>> categoryListMap = postCategoryService
.listCategoryListMap(postIds);
// Get comment count
Map<Integer, Long> commentCountMap = postCommentService.countByPostIds(postIds);
@ -496,9 +538,11 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
String pathSuffix = optionService.getByPropertyOrDefault(PermalinkProperties.PATH_SUFFIX, String.class, "");
String pathSuffix = optionService
.getByPropertyOrDefault(PermalinkProperties.PATH_SUFFIX, String.class, "");
String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, "");
String archivesPrefix = optionService
.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, "");
return postPage.map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
@ -579,14 +623,15 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
/**
* Converts to post detail vo.
*
* @param post post must not be null
* @param tags tags
* @param categories categories
* @param post post must not be null
* @param tags tags
* @param categories categories
* @param postMetaList postMetas
* @return post detail vo
*/
@NonNull
private PostDetailVO convertTo(@NonNull Post post, @Nullable List<Tag> tags, @Nullable List<Category> categories, List<PostMeta> postMetaList) {
private PostDetailVO convertTo(@NonNull Post post, @Nullable List<Tag> tags,
@Nullable List<Category> categories, List<PostMeta> postMetaList) {
Assert.notNull(post, "Post must not be null");
// Convert to base detail vo
@ -641,17 +686,20 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
postSubquery.select(postCategoryRoot.get("postId"));
postSubquery.where(
criteriaBuilder.equal(root.get("id"), postCategoryRoot.get("postId")),
criteriaBuilder.equal(postCategoryRoot.get("categoryId"), postQuery.getCategoryId()));
criteriaBuilder.equal(postCategoryRoot.get("categoryId"),
postQuery.getCategoryId()));
predicates.add(criteriaBuilder.exists(postSubquery));
}
if (postQuery.getKeyword() != null) {
// Format like condition
String likeCondition = String.format("%%%s%%", StringUtils.strip(postQuery.getKeyword()));
String likeCondition = String
.format("%%%s%%", StringUtils.strip(postQuery.getKeyword()));
// Build like predicate
Predicate titleLike = criteriaBuilder.like(root.get("title"), likeCondition);
Predicate originalContentLike = criteriaBuilder.like(root.get("originalContent"), likeCondition);
Predicate originalContentLike = criteriaBuilder
.like(root.get("originalContent"), likeCondition);
predicates.add(criteriaBuilder.or(titleLike, originalContentLike));
}
@ -660,7 +708,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
};
}
private PostDetailVO createOrUpdate(@NonNull Post post, Set<Integer> tagIds, Set<Integer> categoryIds, Set<PostMeta> postMetas) {
private PostDetailVO createOrUpdate(@NonNull Post post, Set<Integer> tagIds,
Set<Integer> categoryIds, Set<PostMeta> postMetas) {
Assert.notNull(post, "Post param must not be null");
// Create or update post
@ -677,17 +726,21 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
List<Category> categories = categoryService.listAllByIds(categoryIds);
// Create post tags
List<PostTag> postTags = postTagService.mergeOrCreateByIfAbsent(post.getId(), ServiceUtils.fetchProperty(tags, Tag::getId));
List<PostTag> postTags = postTagService.mergeOrCreateByIfAbsent(post.getId(),
ServiceUtils.fetchProperty(tags, Tag::getId));
log.debug("Created post tags: [{}]", postTags);
// Create post categories
List<PostCategory> postCategories = postCategoryService.mergeOrCreateByIfAbsent(post.getId(), ServiceUtils.fetchProperty(categories, Category::getId));
List<PostCategory> postCategories = postCategoryService
.mergeOrCreateByIfAbsent(post.getId(),
ServiceUtils.fetchProperty(categories, Category::getId));
log.debug("Created post categories: [{}]", postCategories);
// Create post meta data
List<PostMeta> postMetaList = postMetaService.createOrUpdateByPostId(post.getId(), postMetas);
List<PostMeta> postMetaList = postMetaService
.createOrUpdateByPostId(post.getId(), postMetas);
log.debug("Created post postMetas: [{}]", postMetaList);
// Convert to post detail vo
@ -698,4 +751,77 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
public void publishVisitEvent(Integer postId) {
eventPublisher.publishEvent(new PostVisitEvent(this, postId));
}
@Override
public @NotNull AdjacentPostVO getAdjacentPosts(Post currentPost) {
Assert.notNull(currentPost, "Post must not be null");
// get pageable post list
List<Post> postList = new ArrayList<>();
// init fist page && default page size
Integer page = 1;
Integer defaultPageSize = 500;
boolean needNext = true;
// get custom sort type
Sort sort = getPostDefaultSort();
Pageable pageable = null;
PostStatus postStatus = PostStatus.PUBLISHED;
long totalCount = countByStatus(postStatus);
while (needNext && totalCount > postList.size()) {
pageable = PageRequest
.of(page >= 1 ? page - 1 : page, defaultPageSize, sort);
Page<Post> postPage = pageBy(postStatus, pageable);
List<Post> pageablePostList = postPage.getContent();
if (pageablePostList.size() == 0) {
break;
}
postList.addAll(postPage.getContent());
if (postList.stream().filter(it -> it.getId().equals(currentPost.getId())).count() == 1
&& !postList.stream().reduce((first, second) -> second).get().getId()
.equals(currentPost.getId())) {
// contains the post && the post is not in the end
needNext = false;
}
page++;
}
if (CollectionUtils.isEmpty(postList)) {
// if post list is empty, return empty object
return AdjacentPostVO.builder().build();
}
// get current post index in post list
List<Integer> idList = postList.stream().map(Post::getId).collect(Collectors.toList());
Integer index = idList.indexOf(currentPost.getId());
if (index == -1) {
// if not found, return empty object
return AdjacentPostVO.builder().build();
}
AdjacentPostVO adjacentPostVO = new AdjacentPostVO();
//setup pre
//TODO convert POST to PostVO (with fullPath)
if (index > 0) {
adjacentPostVO.setPrePost(postList.get(index - 1));
}
// setup next
if (index < postList.size() - 1) {
adjacentPostVO.setNextPost(postList.get(index + 1));
}
return adjacentPostVO;
}
@Override
public @NotNull Sort getPostDefaultSort() {
String indexSort = optionService.getByPropertyOfNonNull(PostProperties.INDEX_SORT)
.toString();
return Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort)).and(Sort.by(DESC, "id"));
}
}

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.PageUtil;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@ -30,6 +31,7 @@ import run.halo.app.model.properties.PostProperties;
import run.halo.app.model.properties.StaticDeployProperties;
import run.halo.app.model.support.HaloConst;
import run.halo.app.model.support.StaticPageFile;
import run.halo.app.model.vo.AdjacentPostVO;
import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.model.vo.SheetDetailVO;
@ -329,8 +331,10 @@ public class StaticPageServiceImpl implements StaticPageService {
for (Post post : posts) {
log.info("Generate archives/{}/index.html", post.getUrl());
ModelMap model = new ModelMap();
postService.getNextPost(post.getCreateTime()).ifPresent(nextPost -> model.addAttribute("nextPost", nextPost));
postService.getPrePost(post.getCreateTime()).ifPresent(prePost -> model.addAttribute("prePost", prePost));
AdjacentPostVO adjacentPostVO = postService.getAdjacentPosts(post);
adjacentPostVO.getOptionalPrePost().ifPresent(prePost -> model.addAttribute("prePost", prePost));
adjacentPostVO.getOptionalNextPost().ifPresent(nextPost -> model.addAttribute("nextPost", nextPost));
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
List<Tag> tags = postTagService.listTagsBy(post.getId());