Add assembler for post and sheet to replace service convert (#1691)

pull/1697/head^2
guqing 2022-03-03 11:15:56 +08:00 committed by GitHub
parent 52b3e4f605
commit 68d263bef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1256 additions and 864 deletions

View File

@ -35,6 +35,7 @@ import run.halo.app.model.params.PostQuery;
import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.assembler.PostAssembler;
import run.halo.app.utils.HaloUtils;
/**
@ -55,12 +56,16 @@ public class PostController {
private final OptionService optionService;
private final PostAssembler postAssembler;
public PostController(PostService postService,
AbstractStringCacheStore cacheStore,
OptionService optionService) {
OptionService optionService,
PostAssembler postAssembler) {
this.postService = postService;
this.cacheStore = cacheStore;
this.optionService = optionService;
this.postAssembler = postAssembler;
}
@GetMapping
@ -71,17 +76,17 @@ public class PostController {
@RequestParam(value = "more", defaultValue = "true") Boolean more) {
Page<Post> postPage = postService.pageBy(postQuery, pageable);
if (more) {
return postService.convertToListVo(postPage, true);
return postAssembler.convertToListVo(postPage);
}
return postService.convertToSimple(postPage);
return postAssembler.convertToSimple(postPage);
}
@GetMapping("latest")
@ApiOperation("Pages latest post")
public List<BasePostMinimalDTO> pageLatest(
@RequestParam(name = "top", defaultValue = "10") int top) {
return postService.convertToMinimal(postService.pageLatest(top).getContent());
return postAssembler.convertToMinimal(postService.pageLatest(top).getContent());
}
@GetMapping("status/{status}")
@ -93,17 +98,17 @@ public class PostController {
Page<Post> posts = postService.pageBy(status, pageable);
if (more) {
return postService.convertToListVo(posts, true);
return postAssembler.convertToListVo(posts);
}
return postService.convertToSimple(posts);
return postAssembler.convertToSimple(posts);
}
@GetMapping("{postId:\\d+}")
@ApiOperation("Gets a post")
public PostDetailVO getBy(@PathVariable("postId") Integer postId) {
Post post = postService.getWithLatestContentById(postId);
return postService.convertToDetailVo(post, true);
return postAssembler.convertToDetailVo(post);
}
@PutMapping("{postId:\\d+}/likes")
@ -164,7 +169,7 @@ public class PostController {
// Update draft content
Post post = postService.updateDraftContent(formattedContent,
contentParam.getOriginalContent(), postId);
return postService.convertToDetail(post);
return postAssembler.convertToDetail(post);
}
@DeleteMapping("{postId:\\d+}")
@ -187,7 +192,7 @@ public class PostController {
post.setSlug(URLEncoder.encode(post.getSlug(), StandardCharsets.UTF_8.name()));
BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post);
BasePostMinimalDTO postMinimalDTO = postAssembler.convertToMinimal(post);
String token = HaloUtils.simpleUUID();

View File

@ -33,6 +33,7 @@ import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetService;
import run.halo.app.service.assembler.SheetAssembler;
import run.halo.app.utils.HaloUtils;
/**
@ -52,19 +53,23 @@ public class SheetController {
private final OptionService optionService;
private final SheetAssembler sheetAssembler;
public SheetController(SheetService sheetService,
AbstractStringCacheStore cacheStore,
OptionService optionService) {
OptionService optionService,
SheetAssembler sheetAssembler) {
this.sheetService = sheetService;
this.cacheStore = cacheStore;
this.optionService = optionService;
this.sheetAssembler = sheetAssembler;
}
@GetMapping("{sheetId:\\d+}")
@ApiOperation("Gets a sheet")
public SheetDetailVO getBy(@PathVariable("sheetId") Integer sheetId) {
Sheet sheet = sheetService.getWithLatestContentById(sheetId);
return sheetService.convertToDetailVo(sheet);
return sheetAssembler.convertToDetailVo(sheet);
}
@GetMapping
@ -72,7 +77,7 @@ public class SheetController {
public Page<SheetListVO> pageBy(
@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
Page<Sheet> sheetPage = sheetService.pageBy(pageable);
return sheetService.convertToListVo(sheetPage);
return sheetAssembler.convertToListVo(sheetPage);
}
@GetMapping("independent")
@ -88,7 +93,7 @@ public class SheetController {
Boolean autoSave) {
Sheet sheet =
sheetService.createBy(sheetParam.convertTo(), sheetParam.getSheetMetas(), autoSave);
return sheetService.convertToDetailVo(sheet);
return sheetAssembler.convertToDetailVo(sheet);
}
@PutMapping("{sheetId:\\d+}")
@ -104,7 +109,7 @@ public class SheetController {
Sheet sheet = sheetService.updateBy(sheetToUpdate, sheetParam.getSheetMetas(), autoSave);
return sheetService.convertToDetailVo(sheet);
return sheetAssembler.convertToDetailVo(sheet);
}
@PutMapping("{sheetId:\\d+}/{status}")
@ -132,14 +137,14 @@ public class SheetController {
// Update draft content
Sheet sheet = sheetService.updateDraftContent(formattedContent,
contentParam.getOriginalContent(), sheetId);
return sheetService.convertToDetail(sheet);
return sheetAssembler.convertToDetail(sheet);
}
@DeleteMapping("{sheetId:\\d+}")
@ApiOperation("Deletes a sheet")
public SheetDetailVO deleteBy(@PathVariable("sheetId") Integer sheetId) {
Sheet sheet = sheetService.removeById(sheetId);
return sheetService.convertToDetailVo(sheet);
return sheetAssembler.convertToDetailVo(sheet);
}
@GetMapping("preview/{sheetId:\\d+}")
@ -150,7 +155,7 @@ public class SheetController {
sheet.setSlug(URLEncoder.encode(sheet.getSlug(), StandardCharsets.UTF_8.name()));
BasePostMinimalDTO sheetMinimalDTO = sheetService.convertToMinimal(sheet);
BasePostMinimalDTO sheetMinimalDTO = sheetAssembler.convertToMinimal(sheet);
String token = HaloUtils.simpleUUID();

View File

@ -43,6 +43,7 @@ import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* @author ryanwang
@ -78,6 +79,8 @@ public class ContentContentController {
private final ThemeService themeService;
private final PostRenderAssembler postRenderAssembler;
private final ContentAuthenticationManager providerManager;
public ContentContentController(PostModel postModel,
@ -92,6 +95,7 @@ public class ContentContentController {
SheetService sheetService,
CategoryService categoryService,
ThemeService themeService,
PostRenderAssembler postRenderAssembler,
ContentAuthenticationManager providerManager) {
this.postModel = postModel;
this.sheetModel = sheetModel;
@ -105,6 +109,7 @@ public class ContentContentController {
this.sheetService = sheetService;
this.categoryService = categoryService;
this.themeService = themeService;
this.postRenderAssembler = postRenderAssembler;
this.providerManager = providerManager;
}
@ -270,7 +275,7 @@ public class ContentContentController {
authRequest.setPrincipal(EncryptTypeEnum.POST.getName());
try {
providerManager.authenticate(authRequest);
BasePostMinimalDTO basePostMinimal = postService.convertToMinimal(post);
BasePostMinimalDTO basePostMinimal = postRenderAssembler.convertToMinimal(post);
return "redirect:" + buildRedirectUrl(basePostMinimal.getFullPath());
} catch (AuthenticationException e) {
request.setAttribute("errorMsg", e.getMessage());

View File

@ -30,7 +30,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import run.halo.app.model.dto.CategoryDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Post;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.PostDetailVO;
@ -38,6 +37,7 @@ import run.halo.app.service.CategoryService;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* @author ryanwang
@ -58,6 +58,8 @@ public class ContentFeedController {
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final CategoryService categoryService;
private final PostCategoryService postCategoryService;
@ -67,11 +69,12 @@ public class ContentFeedController {
private final FreeMarkerConfigurer freeMarker;
public ContentFeedController(PostService postService,
CategoryService categoryService,
PostRenderAssembler postRenderAssembler, CategoryService categoryService,
PostCategoryService postCategoryService,
OptionService optionService,
FreeMarkerConfigurer freeMarker) {
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.categoryService = categoryService;
this.postCategoryService = postCategoryService;
this.optionService = optionService;
@ -258,14 +261,7 @@ public class ContentFeedController {
@NonNull
private Page<PostDetailVO> convertToDetailPageVo(Page<Post> postPage) {
Assert.notNull(postPage, "The postPage must not be null.");
// Populate post content
postPage.getContent().forEach(post -> {
Content postContent = postService.getContentById(post.getId());
post.setContent(Content.PatchedContent.of(postContent));
});
Page<PostDetailVO> posts = postService.convertToDetailVo(postPage);
Page<PostDetailVO> posts = postRenderAssembler.convertToDetailVo(postPage);
posts.getContent().forEach(postDetailVO -> {
postDetailVO.setContent(
RegExUtils.replaceAll(postDetailVO.getContent(), XML_INVALID_CHAR, ""));

View File

@ -19,6 +19,7 @@ import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Search controller.
@ -32,13 +33,17 @@ public class ContentSearchController {
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final OptionService optionService;
private final ThemeService themeService;
public ContentSearchController(PostService postService, OptionService optionService,
public ContentSearchController(PostService postService,
PostRenderAssembler postRenderAssembler, OptionService optionService,
ThemeService themeService) {
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.optionService = optionService;
this.themeService = themeService;
}
@ -71,7 +76,7 @@ public class ContentSearchController {
final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
final Page<Post> postPage = postService.pageBy(keyword, pageable);
final Page<PostListVO> posts = postService.convertToListVo(postPage);
final Page<PostListVO> posts = postRenderAssembler.convertToListVo(postPage);
model.addAttribute("is_search", true);
model.addAttribute("keyword", HtmlUtils.htmlEscape(keyword));

View File

@ -29,7 +29,7 @@ import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.CategoryService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Content category controller.
@ -45,7 +45,7 @@ public class CategoryController {
private final PostCategoryService postCategoryService;
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final CategoryAuthentication categoryAuthentication;
@ -53,12 +53,12 @@ public class CategoryController {
public CategoryController(CategoryService categoryService,
PostCategoryService postCategoryService,
PostService postService,
PostRenderAssembler postRenderAssembler,
CategoryAuthentication categoryAuthentication,
ContentAuthenticationManager contentAuthenticationManager) {
this.categoryService = categoryService;
this.postCategoryService = postCategoryService;
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.categoryAuthentication = categoryAuthentication;
this.contentAuthenticationManager = contentAuthenticationManager;
}
@ -90,7 +90,7 @@ public class CategoryController {
Page<Post> postPage =
postCategoryService.pagePostBy(category.getId(), statusesToQuery, pageable);
return postService.convertToListVo(postPage);
return postRenderAssembler.convertToListVo(postPage);
}
private boolean allowIntimatePosts(Integer categoryId, String password) {

View File

@ -22,10 +22,11 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.HtmlUtils;
import run.halo.app.cache.lock.CacheLock;
import run.halo.app.cache.lock.CacheParam;
import run.halo.app.controller.content.auth.PostAuthentication;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.dto.BaseCommentDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostComment;
import run.halo.app.model.enums.CommentStatus;
@ -40,6 +41,7 @@ import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCommentService;
import run.halo.app.service.PostService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Content post controller.
@ -59,18 +61,25 @@ public class PostController {
private final OptionService optionService;
private final PostRenderAssembler postRenderAssembler;
private final PostAuthentication postAuthentication;
public PostController(PostService postService,
PostCommentService postCommentService,
OptionService optionService) {
OptionService optionService, PostRenderAssembler postRenderAssembler,
PostAuthentication postAuthentication) {
this.postService = postService;
this.postCommentService = postCommentService;
this.optionService = optionService;
this.postRenderAssembler = postRenderAssembler;
this.postAuthentication = postAuthentication;
}
//CS304 issue for https://github.com/halo-dev/halo/issues/1351
/**
* Enable users search published articles with keywords
* Enable users search published articles with keywords.
*
* @param pageable store the priority of the sort algorithm
* @param keyword search articles with keyword
@ -88,7 +97,7 @@ public class PostController {
postQuery.setCategoryId(categoryId);
postQuery.setStatuses(Set.of(PostStatus.PUBLISHED));
Page<Post> postPage = postService.pageBy(postQuery, pageable);
return postService.convertToListVo(postPage, true);
return postRenderAssembler.convertToListVo(postPage);
}
@PostMapping(value = "search")
@ -96,7 +105,7 @@ public class PostController {
public Page<BasePostSimpleDTO> pageBy(@RequestParam(value = "keyword") String keyword,
@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
Page<Post> postPage = postService.pageBy(keyword, pageable);
return postService.convertToSimple(postPage);
return postRenderAssembler.convertToSimple(postPage);
}
@GetMapping("{postId:\\d+}")
@ -107,8 +116,10 @@ public class PostController {
@RequestParam(value = "sourceDisabled", required = false, defaultValue = "false")
Boolean sourceDisabled) {
Post post = postService.getById(postId);
post.setContent(Content.PatchedContent.of(postService.getContentById(postId)));
PostDetailVO postDetailVO = postService.convertToDetailVo(post);
checkAuthenticate(postId);
PostDetailVO postDetailVO = postRenderAssembler.convertToDetailVo(post);
if (formatDisabled) {
// Clear the format content
@ -133,8 +144,10 @@ public class PostController {
@RequestParam(value = "sourceDisabled", required = false, defaultValue = "false")
Boolean sourceDisabled) {
Post post = postService.getBySlug(slug);
post.setContent(Content.PatchedContent.of(postService.getContentById(post.getId())));
PostDetailVO postDetailVO = postService.convertToDetailVo(post);
checkAuthenticate(post.getId());
PostDetailVO postDetailVO = postRenderAssembler.convertToDetailVo(post);
if (formatDisabled) {
// Clear the format content
@ -157,9 +170,8 @@ public class PostController {
Post post = postService.getById(postId);
Post prevPost =
postService.getPrevPost(post).orElseThrow(() -> new NotFoundException("查询不到该文章的信息"));
prevPost.setContent(
Content.PatchedContent.of(postService.getContentById(prevPost.getId())));
return postService.convertToDetailVo(prevPost);
checkAuthenticate(prevPost.getId());
return postRenderAssembler.convertToDetailVo(prevPost);
}
@GetMapping("{postId:\\d+}/next")
@ -168,15 +180,15 @@ public class PostController {
Post post = postService.getById(postId);
Post nextPost =
postService.getNextPost(post).orElseThrow(() -> new NotFoundException("查询不到该文章的信息"));
nextPost.setContent(
Content.PatchedContent.of(postService.getContentById(nextPost.getId())));
return postService.convertToDetailVo(nextPost);
checkAuthenticate(nextPost.getId());
return postRenderAssembler.convertToDetailVo(nextPost);
}
@GetMapping("{postId:\\d+}/comments/top_view")
public Page<CommentWithHasChildrenVO> listTopComments(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
checkAuthenticate(postId);
return postCommentService.pageTopCommentsBy(postId, CommentStatus.PUBLISHED,
PageRequest.of(page, optionService.getCommentPageSize(), sort));
}
@ -185,6 +197,7 @@ public class PostController {
public List<BaseCommentDTO> listChildrenBy(@PathVariable("postId") Integer postId,
@PathVariable("commentParentId") Long commentParentId,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
checkAuthenticate(postId);
// Find all children comments
List<PostComment> postComments = postCommentService
.listChildrenBy(postId, commentParentId, CommentStatus.PUBLISHED, sort);
@ -198,6 +211,7 @@ public class PostController {
public Page<BaseCommentVO> listCommentsTree(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
checkAuthenticate(postId);
return postCommentService
.pageVosBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
}
@ -207,6 +221,7 @@ public class PostController {
public Page<BaseCommentWithParentVO> listComments(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
checkAuthenticate(postId);
return postCommentService.pageWithParentVoBy(postId,
PageRequest.of(page, optionService.getCommentPageSize(), sort));
}
@ -215,6 +230,7 @@ public class PostController {
@ApiOperation("Comments a post")
@CacheLock(autoDelete = false, traceRequest = true)
public BaseCommentDTO comment(@RequestBody PostCommentParam postCommentParam) {
checkAuthenticate(postCommentParam.getPostId());
postCommentService.validateCommentBlackListStatus();
// Escape content
@ -227,6 +243,13 @@ public class PostController {
@ApiOperation("Likes a post")
@CacheLock(autoDelete = false, traceRequest = true)
public void like(@PathVariable("postId") @CacheParam Integer postId) {
checkAuthenticate(postId);
postService.increaseLike(postId);
}
private void checkAuthenticate(Integer postId) {
if (!postAuthentication.isAuthenticated(postId)) {
throw new ForbiddenException("您没有该分类的访问权限");
}
}
}

View File

@ -21,7 +21,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.HtmlUtils;
import run.halo.app.cache.lock.CacheLock;
import run.halo.app.model.dto.BaseCommentDTO;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetComment;
import run.halo.app.model.enums.CommentStatus;
@ -35,6 +34,7 @@ import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetService;
import run.halo.app.service.assembler.SheetRenderAssembler;
/**
* Content sheet controller.
@ -49,13 +49,18 @@ public class SheetController {
private final SheetService sheetService;
private final SheetRenderAssembler sheetRenderAssembler;
private final SheetCommentService sheetCommentService;
private final OptionService optionService;
public SheetController(SheetService sheetService, SheetCommentService sheetCommentService,
public SheetController(SheetService sheetService,
SheetRenderAssembler sheetRenderAssembler,
SheetCommentService sheetCommentService,
OptionService optionService) {
this.sheetService = sheetService;
this.sheetRenderAssembler = sheetRenderAssembler;
this.sheetCommentService = sheetCommentService;
this.optionService = optionService;
}
@ -65,7 +70,7 @@ public class SheetController {
public Page<SheetListVO> pageBy(
@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
Page<Sheet> sheetPage = sheetService.pageBy(PostStatus.PUBLISHED, pageable);
return sheetService.convertToListVo(sheetPage);
return sheetRenderAssembler.convertToListVo(sheetPage);
}
@GetMapping("{sheetId:\\d+}")
@ -76,8 +81,8 @@ public class SheetController {
@RequestParam(value = "sourceDisabled", required = false, defaultValue = "false")
Boolean sourceDisabled) {
Sheet sheet = sheetService.getById(sheetId);
sheet.setContent(Content.PatchedContent.of(sheetService.getContentById(sheetId)));
SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet);
SheetDetailVO sheetDetailVO = sheetRenderAssembler.convertToDetailVo(sheet);
if (formatDisabled) {
// Clear the format content
@ -102,8 +107,7 @@ public class SheetController {
@RequestParam(value = "sourceDisabled", required = false, defaultValue = "false")
Boolean sourceDisabled) {
Sheet sheet = sheetService.getBySlug(slug);
sheet.setContent(Content.PatchedContent.of(sheetService.getContentById(sheet.getId())));
SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet);
SheetDetailVO sheetDetailVO = sheetRenderAssembler.convertToDetailVo(sheet);
if (formatDisabled) {
// Clear the format content

View File

@ -20,9 +20,9 @@ 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.PostListVO;
import run.halo.app.service.PostService;
import run.halo.app.service.PostTagService;
import run.halo.app.service.TagService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Content tag controller.
@ -39,14 +39,14 @@ public class TagController {
private final PostTagService postTagService;
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
public TagController(TagService tagService,
PostTagService postTagService,
PostService postService) {
PostRenderAssembler postRenderAssembler) {
this.tagService = tagService;
this.postTagService = postTagService;
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
}
@GetMapping
@ -72,6 +72,6 @@ public class TagController {
// Get posts, convert and return
Page<Post> postPage =
postTagService.pagePostsBy(tag.getId(), PostStatus.PUBLISHED, pageable);
return postService.convertToListVo(postPage);
return postRenderAssembler.convertToListVo(postPage);
}
}

View File

@ -37,7 +37,7 @@ public class CategoryAuthentication implements ContentAuthentication {
@Override
public boolean isAuthenticated(Integer categoryId) {
Category category = categoryService.getById(categoryId);
if (category.getPassword() == null) {
if (StringUtils.isBlank(category.getPassword())) {
// All parent category is not encrypted
if (categoryService.lookupFirstEncryptedBy(category.getId()).isEmpty()) {
return true;

View File

@ -95,6 +95,18 @@ public class ContentAuthenticationManager {
return postAuthentication;
}
}
for (Category category : encryptedCategories) {
boolean authenticated = categoryService.lookupFirstEncryptedBy(category.getId())
.filter(parentCategory -> StringUtils.equals(parentCategory.getPassword(),
authRequest.getPassword()))
.isPresent();
if (authenticated) {
postAuthentication.setAuthenticated(post.getId(), true);
return postAuthentication;
}
}
throw new AuthenticationException("密码不正确");
}
}

View File

@ -1,11 +1,15 @@
package run.halo.app.controller.content.auth;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostCategory;
import run.halo.app.model.enums.EncryptTypeEnum;
import run.halo.app.service.CategoryService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
/**
@ -18,12 +22,21 @@ import run.halo.app.service.PostService;
public class PostAuthentication implements ContentAuthentication {
private final PostService postService;
private final CategoryService categoryService;
private final PostCategoryService postCategoryService;
private final AbstractStringCacheStore cacheStore;
private final CategoryAuthentication categoryAuthentication;
public PostAuthentication(PostService postService,
AbstractStringCacheStore cacheStore) {
CategoryService categoryService,
PostCategoryService postCategoryService,
AbstractStringCacheStore cacheStore,
CategoryAuthentication categoryAuthentication) {
this.postService = postService;
this.categoryService = categoryService;
this.postCategoryService = postCategoryService;
this.cacheStore = cacheStore;
this.categoryAuthentication = categoryAuthentication;
}
@Override
@ -34,8 +47,20 @@ public class PostAuthentication implements ContentAuthentication {
@Override
public boolean isAuthenticated(Integer postId) {
Post post = postService.getById(postId);
if (post.getPassword() == null) {
return true;
if (StringUtils.isBlank(post.getPassword())) {
List<PostCategory> postCategories = postCategoryService.listByPostId(postId);
boolean categoryEncrypted = postCategories.stream()
.anyMatch(postCategory -> categoryService.isPrivate(postCategory.getCategoryId()));
if (!categoryEncrypted) {
return true;
}
boolean anyCategoryAuthenticated = postCategories.stream()
.anyMatch(postCategory ->
categoryAuthentication.isAuthenticated(postCategory.getCategoryId()));
if (anyCategoryAuthenticated) {
return true;
}
}
String sessionId = getSessionId();

View File

@ -23,13 +23,14 @@ import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.CategoryService;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Category Model.
*
* @author ryanwang
* @author guqing
* @date 2020-01-11
*/
@Component
@ -41,7 +42,7 @@ public class CategoryModel {
private final PostCategoryService postCategoryService;
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final OptionService optionService;
@ -50,13 +51,12 @@ public class CategoryModel {
public CategoryModel(CategoryService categoryService,
ThemeService themeService,
PostCategoryService postCategoryService,
PostService postService,
OptionService optionService,
PostRenderAssembler postRenderAssembler, OptionService optionService,
CategoryAuthentication categoryAuthentication) {
this.categoryService = categoryService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.optionService = optionService;
this.categoryAuthentication = categoryAuthentication;
}
@ -97,7 +97,7 @@ public class CategoryModel {
}
Set<PostStatus> statuses = Sets.immutableEnumSet(PostStatus.PUBLISHED);
if (StringUtils.isNotBlank(category.getPassword())) {
if (categoryService.isPrivate(category.getId())) {
statuses = Sets.immutableEnumSet(PostStatus.INTIMATE);
}
@ -108,7 +108,7 @@ public class CategoryModel {
Sort.by(DESC, "topPriority", "createTime"));
Page<Post> postPage =
postCategoryService.pagePostBy(category.getId(), statuses, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
Page<PostListVO> posts = postRenderAssembler.convertToListVo(postPage);
// Generate meta description.
if (StringUtils.isNotEmpty(category.getDescription())) {

View File

@ -17,8 +17,6 @@ import run.halo.app.controller.content.auth.PostAuthentication;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.PostMeta;
import run.halo.app.model.entity.Tag;
@ -34,6 +32,7 @@ import run.halo.app.service.PostService;
import run.halo.app.service.PostTagService;
import run.halo.app.service.TagService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Post Model
@ -45,6 +44,8 @@ import run.halo.app.service.ThemeService;
@Component
public class PostModel {
private final PostRenderAssembler postRenderAssembler;
private final PostService postService;
private final ThemeService themeService;
@ -65,7 +66,8 @@ public class PostModel {
private final PostAuthentication postAuthentication;
public PostModel(PostService postService,
public PostModel(PostRenderAssembler postRenderAssembler,
PostService postService,
ThemeService themeService,
PostCategoryService postCategoryService,
CategoryService categoryService,
@ -75,6 +77,7 @@ public class PostModel {
OptionService optionService,
AbstractStringCacheStore cacheStore,
PostAuthentication postAuthentication) {
this.postRenderAssembler = postRenderAssembler;
this.postService = postService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
@ -117,21 +120,16 @@ public class PostModel {
return "common/template/" + POST_PASSWORD_TEMPLATE;
}
if (StringUtils.isNotBlank(token)) {
post = postService.getWithLatestContentById(post.getId());
} else {
post = postService.getById(post.getId());
// Set post content
Content postContent = postService.getContentById(post.getId());
post.setContent(PatchedContent.of(postContent));
}
post = postService.getById(post.getId());
postService.publishVisitEvent(post.getId());
postService.getPrevPost(post).ifPresent(
prevPost -> model.addAttribute("prevPost", postService.convertToDetailVo(prevPost)));
postService.getNextPost(post).ifPresent(
nextPost -> model.addAttribute("nextPost", postService.convertToDetailVo(nextPost)));
postService.getPrevPost(post)
.ifPresent(prevPost -> model.addAttribute("prevPost",
postRenderAssembler.convertToDetailVo(prevPost)));
postService.getNextPost(post)
.ifPresent(nextPost -> model.addAttribute("nextPost",
postRenderAssembler.convertToDetailVo(nextPost)));
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
List<Tag> tags = postTagService.listTagsBy(post.getId());
@ -154,7 +152,13 @@ public class PostModel {
}
model.addAttribute("is_post", true);
model.addAttribute("post", postService.convertToDetailVo(post));
if (StringUtils.isNotBlank(token)) {
model.addAttribute("post", postRenderAssembler.convertToPreviewDetailVo(post));
} else {
model.addAttribute("post", postRenderAssembler.convertToDetailVo(post));
}
model.addAttribute("categories", categoryService.convertTo(categories));
model.addAttribute("tags", tagService.convertTo(tags));
model.addAttribute("metas", postMetaService.convertToMap(metas));
@ -173,7 +177,7 @@ public class PostModel {
.of(page >= 1 ? page - 1 : page, pageSize, postService.getPostDefaultSort());
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
Page<PostListVO> posts = postRenderAssembler.convertToListVo(postPage);
model.addAttribute("is_index", true);
model.addAttribute("posts", posts);
@ -189,9 +193,10 @@ public class PostModel {
Page<Post> postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
Page<PostListVO> posts = postRenderAssembler.convertToListVo(postPage);
List<ArchiveYearVO> archives = postService.convertToYearArchives(postPage.getContent());
List<ArchiveYearVO> archives =
postRenderAssembler.convertToYearArchives(postPage.getContent());
model.addAttribute("is_archives", true);
model.addAttribute("posts", posts);

View File

@ -6,8 +6,6 @@ import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetMeta;
import run.halo.app.model.enums.PostStatus;
@ -17,6 +15,7 @@ import run.halo.app.service.OptionService;
import run.halo.app.service.SheetMetaService;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.SheetRenderAssembler;
/**
* Sheet model.
@ -29,6 +28,8 @@ public class SheetModel {
private final SheetService sheetService;
private final SheetRenderAssembler sheetRenderAssembler;
private final SheetMetaService sheetMetaService;
private final AbstractStringCacheStore cacheStore;
@ -38,11 +39,13 @@ public class SheetModel {
private final OptionService optionService;
public SheetModel(SheetService sheetService,
SheetRenderAssembler sheetRenderAssembler,
SheetMetaService sheetMetaService,
AbstractStringCacheStore cacheStore,
ThemeService themeService,
OptionService optionService) {
this.sheetService = sheetService;
this.sheetRenderAssembler = sheetRenderAssembler;
this.sheetMetaService = sheetMetaService;
this.cacheStore = cacheStore;
this.themeService = themeService;
@ -58,12 +61,10 @@ public class SheetModel {
* @return template name
*/
public String content(Sheet sheet, String token, Model model) {
SheetDetailVO sheetDetailVo;
if (StringUtils.isEmpty(token)) {
sheet = sheetService.getBy(PostStatus.PUBLISHED, sheet.getSlug());
//Set sheet content
Content content = sheetService.getContentById(sheet.getId());
sheet.setContent(PatchedContent.of(content));
sheetDetailVo = sheetRenderAssembler.convertToDetailVo(sheet);
} else {
// verify token
String cachedToken = cacheStore.getAny(token, String.class)
@ -71,15 +72,11 @@ public class SheetModel {
if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该页面的访问权限");
}
// render markdown to html when preview sheet
PatchedContent sheetContent = sheetService.getLatestContentById(sheet.getId());
sheet.setContent(sheetContent);
sheetDetailVo = sheetRenderAssembler.convertToPreviewDetailVo(sheet);
}
sheetService.publishVisitEvent(sheet.getId());
SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet);
List<SheetMeta> metas = sheetMetaService.listBy(sheet.getId());
// Generate meta keywords.
@ -98,8 +95,8 @@ public class SheetModel {
}
// sheet and post all can use
model.addAttribute("sheet", sheetDetailVO);
model.addAttribute("post", sheetDetailVO);
model.addAttribute("sheet", sheetDetailVo);
model.addAttribute("post", sheetDetailVo);
model.addAttribute("is_sheet", true);
model.addAttribute("metas", sheetMetaService.convertToMap(metas));

View File

@ -14,10 +14,10 @@ import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import run.halo.app.service.PostTagService;
import run.halo.app.service.TagService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Tag Model.
@ -30,7 +30,7 @@ public class TagModel {
private final TagService tagService;
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final PostTagService postTagService;
@ -38,10 +38,13 @@ public class TagModel {
private final ThemeService themeService;
public TagModel(TagService tagService, PostService postService, PostTagService postTagService,
OptionService optionService, ThemeService themeService) {
public TagModel(TagService tagService,
PostRenderAssembler postRenderAssembler,
PostTagService postTagService,
OptionService optionService,
ThemeService themeService) {
this.tagService = tagService;
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.postTagService = postTagService;
this.optionService = optionService;
this.themeService = themeService;
@ -63,7 +66,7 @@ public class TagModel {
.of(page - 1, optionService.getArchivesPageSize(), Sort.by(DESC, "createTime"));
Page<Post> postPage =
postTagService.pagePostsBy(tag.getId(), PostStatus.PUBLISHED, pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
Page<PostListVO> posts = postRenderAssembler.convertToListVo(postPage);
model.addAttribute("is_tag", true);
model.addAttribute("posts", posts);

View File

@ -18,6 +18,7 @@ import run.halo.app.model.support.HaloConst;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
import run.halo.app.service.PostTagService;
import run.halo.app.service.assembler.PostRenderAssembler;
/**
* Freemarker custom tag of post.
@ -30,15 +31,19 @@ public class PostTagDirective implements TemplateDirectiveModel {
private final PostService postService;
private final PostRenderAssembler postRenderAssembler;
private final PostTagService postTagService;
private final PostCategoryService postCategoryService;
public PostTagDirective(Configuration configuration,
PostService postService,
PostRenderAssembler postRenderAssembler,
PostTagService postTagService,
PostCategoryService postCategoryService) {
this.postService = postService;
this.postRenderAssembler = postRenderAssembler;
this.postTagService = postTagService;
this.postCategoryService = postCategoryService;
configuration.setSharedVariable("postTag", this);
@ -55,7 +60,7 @@ public class PostTagDirective implements TemplateDirectiveModel {
case "latest":
int top = Integer.parseInt(params.get("top").toString());
env.setVariable("posts", builder.build()
.wrap(postService.convertToListVo(postService.listLatest(top))));
.wrap(postRenderAssembler.convertToListVo(postService.listLatest(top))));
break;
case "count":
env.setVariable("count",
@ -77,9 +82,11 @@ public class PostTagDirective implements TemplateDirectiveModel {
break;
case "listByCategoryId":
Integer categoryId = Integer.parseInt(params.get("categoryId").toString());
env.setVariable("posts", builder.build().wrap(postService.convertToListVo(
postCategoryService.listPostBy(categoryId,
Sets.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE)))));
env.setVariable("posts", builder.build()
.wrap(postRenderAssembler.convertToListVo(
postCategoryService.listPostBy(categoryId,
Sets.immutableEnumSet(PostStatus.PUBLISHED,
PostStatus.INTIMATE)))));
break;
case "listByCategorySlug":
String categorySlug = params.get("categorySlug").toString();
@ -87,17 +94,22 @@ public class PostTagDirective implements TemplateDirectiveModel {
postCategoryService.listPostBy(categorySlug,
Sets.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE));
env.setVariable("posts",
builder.build().wrap(postService.convertToListVo(posts)));
builder.build().wrap(postRenderAssembler.convertToListVo(posts)));
break;
case "listByTagId":
Integer tagId = Integer.parseInt(params.get("tagId").toString());
env.setVariable("posts", builder.build().wrap(postService
env.setVariable("posts", builder.build().wrap(postRenderAssembler
.convertToListVo(postTagService.listPostsBy(tagId, PostStatus.PUBLISHED))));
break;
case "listByTagSlug":
String tagSlug = params.get("tagSlug").toString();
env.setVariable("posts", builder.build().wrap(postService.convertToListVo(
postTagService.listPostsBy(tagSlug, PostStatus.PUBLISHED))));
env.setVariable("posts", builder.build()
.wrap(
postRenderAssembler.convertToListVo(
postTagService.listPostsBy(tagSlug, PostStatus.PUBLISHED)
)
)
);
break;
default:
break;

View File

@ -27,6 +27,8 @@ import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.UserService;
import run.halo.app.service.assembler.PostAssembler;
import run.halo.app.service.assembler.SheetAssembler;
import run.halo.app.utils.ValidationUtils;
/**
@ -52,8 +54,12 @@ public class CommentEventListener {
private final PostService postService;
private final PostAssembler postAssembler;
private final SheetService sheetService;
private final SheetAssembler sheetAssembler;
private final JournalService journalService;
private final UserService userService;
@ -63,7 +69,9 @@ public class CommentEventListener {
public CommentEventListener(MailService mailService, OptionService optionService,
PostCommentService postCommentService, SheetCommentService sheetCommentService,
JournalCommentService journalCommentService, PostService postService,
SheetService sheetService, JournalService journalService, UserService userService,
PostAssembler postAssembler, SheetService sheetService,
SheetAssembler sheetAssembler, JournalService journalService,
UserService userService,
ThemeService themeService) {
this.mailService = mailService;
this.optionService = optionService;
@ -71,7 +79,9 @@ public class CommentEventListener {
this.sheetCommentService = sheetCommentService;
this.journalCommentService = journalCommentService;
this.postService = postService;
this.postAssembler = postAssembler;
this.sheetService = sheetService;
this.sheetAssembler = sheetAssembler;
this.journalService = journalService;
this.userService = userService;
this.themeService = themeService;
@ -109,7 +119,7 @@ public class CommentEventListener {
log.debug("Got post comment: [{}]", postComment);
BasePostMinimalDTO post =
postService.convertToMinimal(postService.getById(postComment.getPostId()));
postAssembler.convertToMinimal(postService.getById(postComment.getPostId()));
data.put("pageFullPath", enabledAbsolutePath ? post.getFullPath() :
optionService.getBlogBaseUrl() + post.getFullPath());
@ -127,7 +137,7 @@ public class CommentEventListener {
log.debug("Got sheet comment: [{}]", sheetComment);
BasePostMinimalDTO sheet =
sheetService.convertToMinimal(sheetService.getById(sheetComment.getPostId()));
sheetAssembler.convertToMinimal(sheetService.getById(sheetComment.getPostId()));
data.put("pageFullPath", enabledAbsolutePath ? sheet.getFullPath() :
optionService.getBlogBaseUrl() + sheet.getFullPath());
@ -211,7 +221,7 @@ public class CommentEventListener {
baseAuthorEmail = baseComment.getEmail();
BasePostMinimalDTO post =
postService.convertToMinimal(postService.getById(postComment.getPostId()));
postAssembler.convertToMinimal(postService.getById(postComment.getPostId()));
data.put("pageFullPath", enabledAbsolutePath ? post.getFullPath() :
optionService.getBlogBaseUrl() + post.getFullPath());
@ -244,7 +254,7 @@ public class CommentEventListener {
baseAuthorEmail = baseComment.getEmail();
BasePostMinimalDTO sheet =
sheetService.convertToMinimal(sheetService.getById(sheetComment.getPostId()));
sheetAssembler.convertToMinimal(sheetService.getById(sheetComment.getPostId()));
data.put("pageFullPath", enabledAbsolutePath ? sheet.getFullPath() :
optionService.getBlogBaseUrl() + sheet.getFullPath());

View File

@ -46,13 +46,13 @@ public class PostRefreshStatusListener {
return;
}
boolean isPrivate = categoryService.isPrivate(category.getId());
if (!isPrivate) {
return;
}
List<Post> posts = postCategoryService.listPostBy(category.getId());
posts.forEach(post -> {
post.setStatus(PostStatus.INTIMATE);
});
if (isPrivate) {
posts.forEach(post -> post.setStatus(PostStatus.INTIMATE));
} else {
posts.forEach(post -> post.setStatus(PostStatus.DRAFT));
}
postService.updateInBatch(posts);
}

View File

@ -15,7 +15,6 @@ import run.halo.app.model.params.PostQuery;
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.model.vo.PostMarkdownVO;
import run.halo.app.service.base.BasePostService;
@ -187,22 +186,6 @@ public interface PostService extends BasePostService<Post> {
@NonNull
List<ArchiveMonthVO> listMonthArchives();
/**
* Convert to year archives
*
* @param posts posts must not be null
* @return list of ArchiveYearVO
*/
List<ArchiveYearVO> convertToYearArchives(@NonNull List<Post> posts);
/**
* Convert to month archives
*
* @param posts posts must not be null
* @return list of ArchiveMonthVO
*/
List<ArchiveMonthVO> convertToMonthArchives(@NonNull List<Post> posts);
/**
* Import post from markdown document.
*
@ -231,61 +214,6 @@ public interface PostService extends BasePostService<Post> {
@NonNull
String exportMarkdown(@NonNull Post post);
/**
* Converts to detail vo.
*
* @param post post must not be null
* @return post detail vo
*/
@NonNull
PostDetailVO convertToDetailVo(@NonNull Post post);
/**
* Converts to a page of detail vo.
*
* @param postPage post page must not be null
* @return a page of post detail vo
*/
Page<PostDetailVO> convertToDetailVo(@NonNull Page<Post> postPage);
/**
* Converts to detail vo.
*
* @param post post must not be null
* @param queryEncryptCategory whether to query encryption category
* @return post detail vo
*/
@NonNull
PostDetailVO convertToDetailVo(@NonNull Post post, @NonNull boolean queryEncryptCategory);
/**
* Converts to a page of post list vo.
*
* @param postPage post page must not be null
* @return a page of post list vo
*/
@NonNull
Page<PostListVO> convertToListVo(@NonNull Page<Post> postPage);
/**
* Converts to a page of post list vo.
*
* @param postPage post page must not be null
* @param queryEncryptCategory whether to query encryption category
* @return a page of post list vo
*/
@NonNull
Page<PostListVO> convertToListVo(@NonNull Page<Post> postPage, boolean queryEncryptCategory);
/**
* Converts to a list of post list vo.
*
* @param posts post must not be null
* @return a list of post list vo
*/
@NonNull
List<PostListVO> convertToListVo(@NonNull List<Post> posts);
/**
* Publish a post visit event.
*

View File

@ -2,14 +2,11 @@ package run.halo.app.service;
import java.util.List;
import java.util.Set;
import org.springframework.data.domain.Page;
import org.springframework.lang.NonNull;
import run.halo.app.model.dto.IndependentSheetDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetMeta;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.base.BasePostService;
/**
@ -17,6 +14,7 @@ import run.halo.app.service.base.BasePostService;
*
* @author johnniang
* @author ryanwang
* @author guqing
* @date 2019-04-24
*/
public interface SheetService extends BasePostService<Sheet> {
@ -106,29 +104,10 @@ public interface SheetService extends BasePostService<Sheet> {
@NonNull
List<IndependentSheetDTO> listIndependentSheets();
/**
* Converts to list dto page.
*
* @param sheetPage sheet page must not be nulls
* @return a page of sheet list dto
*/
@NonNull
Page<SheetListVO> convertToListVo(@NonNull Page<Sheet> sheetPage);
/**
* Converts to detail vo.
*
* @param sheet sheet must not be null
* @return sheet detail vo
*/
@NonNull
SheetDetailVO convertToDetailVo(@NonNull Sheet sheet);
/**
* Publish a sheet visit event.
*
* @param sheetId sheetId must not be null
*/
void publishVisitEvent(@NonNull Integer sheetId);
}

View File

@ -0,0 +1,188 @@
package run.halo.app.service.assembler;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.BasePost;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.properties.PostProperties;
import run.halo.app.service.ContentService;
import run.halo.app.service.OptionService;
import run.halo.app.utils.HaloUtils;
/**
* @author guqing
* @date 2022-03-01
*/
public class BasePostAssembler<POST extends BasePost> {
private static final Pattern summaryPattern = Pattern.compile("\t|\r|\n");
private final ContentService contentService;
private final OptionService optionService;
public BasePostAssembler(ContentService contentService,
OptionService optionService) {
this.contentService = contentService;
this.optionService = optionService;
}
/**
* Convert POST to minimal dto.
*
* @param post post must not be null.
* @return minimal dto.
*/
public BasePostMinimalDTO convertToMinimal(POST post) {
Assert.notNull(post, "Post must not be null");
return new BasePostMinimalDTO().convertFrom(post);
}
/**
* Convert list of POST to minimal dto of list.
*
* @param posts posts must not be null.
* @return a list of minimal dto.
*/
@NonNull
public List<BasePostMinimalDTO> convertToMinimal(List<POST> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
/**
* Convert page of POST to minimal dto of page.
*
* @param postPage postPage must not be null.
* @return a page of minimal dto.
*/
@NonNull
public Page<BasePostMinimalDTO> convertToMinimal(Page<POST> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToMinimal);
}
/**
* Convert POST to simple dto.
*
* @param post post must not be null.
* @return simple dto.
*/
@NonNull
public BasePostSimpleDTO convertToSimple(POST post) {
Assert.notNull(post, "Post must not be null");
BasePostSimpleDTO basePostSimpleDTO = new BasePostSimpleDTO().convertFrom(post);
// Set summary
generateAndSetSummaryIfAbsent(post, basePostSimpleDTO);
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(post.getId());
basePostSimpleDTO.setInProgress(isInProcess);
return basePostSimpleDTO;
}
/**
* Convert list of POST to list of simple dto.
*
* @param posts posts must not be null.
* @return a list of simple dto.
*/
@NonNull
public List<BasePostSimpleDTO> convertToSimple(List<POST> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToSimple)
.collect(Collectors.toList());
}
/**
* Convert page of POST to page of simple dto.
*
* @param postPage postPage must not be null.
* @return a page of simple dto.
*/
@NonNull
public Page<BasePostSimpleDTO> convertToSimple(Page<POST> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToSimple);
}
/**
* Convert POST to detail dto.
*
* @param post post must not be null.
* @return detail dto.
*/
@NonNull
public BasePostDetailDTO convertToDetail(POST post) {
Assert.notNull(post, "Post must not be null");
BasePostDetailDTO postDetail = new BasePostDetailDTO().convertFrom(post);
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(post.getId());
postDetail.setInProgress(isInProcess);
return postDetail;
}
@NonNull
protected String generateSummary(@Nullable String htmlContent) {
if (StringUtils.isBlank(htmlContent)) {
return StringUtils.EMPTY;
}
String text = HaloUtils.cleanHtmlTag(htmlContent);
Matcher matcher = summaryPattern.matcher(text);
text = matcher.replaceAll("");
// Get summary length
Integer summaryLength =
optionService.getByPropertyOrDefault(PostProperties.SUMMARY_LENGTH, Integer.class, 150);
return StringUtils.substring(text, 0, summaryLength);
}
protected <T extends BasePostSimpleDTO> void generateAndSetSummaryIfAbsent(POST post,
T postVo) {
Assert.notNull(post, "The post must not be null.");
if (StringUtils.isNotBlank(postVo.getSummary())) {
return;
}
PatchedContent patchedContent = post.getContentOfNullable();
if (patchedContent == null) {
Content postContent = contentService.getById(post.getId());
postVo.setSummary(generateSummary(postContent.getContent()));
} else {
postVo.setSummary(generateSummary(patchedContent.getContent()));
}
}
}

View File

@ -0,0 +1,453 @@
package run.halo.app.service.assembler;
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
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 org.springframework.data.domain.Page;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Content.PatchedContent;
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.CommentStatus;
import run.halo.app.model.enums.PostPermalinkType;
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.service.CategoryService;
import run.halo.app.service.ContentService;
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.PostTagService;
import run.halo.app.service.TagService;
import run.halo.app.utils.DateUtils;
import run.halo.app.utils.ServiceUtils;
/**
* Post assembler.
*
* @author guqing
* @date 2022-03-01
*/
@Component
public class PostAssembler extends BasePostAssembler<Post> {
private final PostTagService postTagService;
private final PostCategoryService postCategoryService;
private final PostMetaService postMetaService;
private final PostCommentService postCommentService;
private final TagService tagService;
private final CategoryService categoryService;
private final ContentService contentService;
private final OptionService optionService;
public PostAssembler(ContentService contentService,
OptionService optionService, PostTagService postTagService,
PostCategoryService postCategoryService,
PostMetaService postMetaService,
PostCommentService postCommentService,
TagService tagService,
CategoryService categoryService) {
super(contentService, optionService);
this.postTagService = postTagService;
this.postCategoryService = postCategoryService;
this.postMetaService = postMetaService;
this.postCommentService = postCommentService;
this.tagService = tagService;
this.categoryService = categoryService;
this.contentService = contentService;
this.optionService = optionService;
}
@Override
public BasePostMinimalDTO convertToMinimal(Post post) {
Assert.notNull(post, "Post must not be null");
BasePostMinimalDTO basePostMinimalDTO = new BasePostMinimalDTO().convertFrom(post);
basePostMinimalDTO.setFullPath(buildFullPath(post));
return basePostMinimalDTO;
}
@Override
public List<BasePostMinimalDTO> convertToMinimal(List<Post> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
/**
* Converts to detail vo.
*
* @param post post must not be null
* @return post detail vo
*/
@NonNull
public PostDetailVO convertToDetailVo(Post post) {
// List tags
List<Tag> tags = postTagService.listTagsBy(post.getId());
// List categories
List<Category> categories = postCategoryService
.listCategoriesBy(post.getId());
// List metas
List<PostMeta> metas = postMetaService.listBy(post.getId());
// Convert to detail vo
return convertTo(post, tags, categories, metas);
}
/**
* Converts to a page of detail vo.
*
* @param postPage post page must not be null
* @return a page of post detail vo
*/
public Page<PostDetailVO> convertToDetailVo(Page<Post> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToDetailVo);
}
/**
* Converts to a page of post list vo.
*
* @param postPage post page must not be null
* @return a page of post list vo
*/
@NonNull
public Page<PostListVO> convertToListVo(Page<Post> postPage) {
Assert.notNull(postPage, "Post page must not be null");
List<Post> posts = postPage.getContent();
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
// Get tag list map
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
// Get category list map
Map<Integer, List<Category>> categoryListMap = postCategoryService
.listCategoryListMap(postIds);
// Get comment count
Map<Integer, Long> commentCountMap = postCommentService.countByStatusAndPostIds(
CommentStatus.PUBLISHED, postIds);
// Get post meta list map
Map<Integer, List<PostMeta>> postMetaListMap = postMetaService.listPostMetaAsMap(postIds);
return postPage.map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postListVO);
Optional.ofNullable(tagListMap.get(post.getId())).orElseGet(LinkedList::new);
// Set tags
postListVO.setTags(Optional.ofNullable(tagListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(tagService::convertTo)
.collect(Collectors.toList()));
// Set categories
postListVO.setCategories(Optional.ofNullable(categoryListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(categoryService::convertTo)
.collect(Collectors.toList()));
// Set post metas
List<PostMeta> metas = Optional.ofNullable(postMetaListMap.get(post.getId()))
.orElseGet(LinkedList::new);
postListVO.setMetas(postMetaService.convertToMap(metas));
// Set comment count
postListVO.setCommentCount(commentCountMap.getOrDefault(post.getId(), 0L));
postListVO.setFullPath(buildFullPath(post));
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(post.getId());
postListVO.setInProgress(isInProcess);
return postListVO;
});
}
public List<PostListVO> convertToListVo(List<Post> posts) {
Assert.notNull(posts, "Post page must not be null");
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
// Get tag list map
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
// Get category list map
Map<Integer, List<Category>> categoryListMap = postCategoryService
.listCategoryListMap(postIds);
// Get comment count
Map<Integer, Long> commentCountMap =
postCommentService.countByStatusAndPostIds(CommentStatus.PUBLISHED, postIds);
// Get post meta list map
Map<Integer, List<PostMeta>> postMetaListMap = postMetaService.listPostMetaAsMap(postIds);
return posts.stream().map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postListVO);
Optional.ofNullable(tagListMap.get(post.getId())).orElseGet(LinkedList::new);
// Set tags
postListVO.setTags(Optional.ofNullable(tagListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(tagService::convertTo)
.collect(Collectors.toList()));
// Set categories
postListVO.setCategories(Optional.ofNullable(categoryListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(categoryService::convertTo)
.collect(Collectors.toList()));
// Set post metas
List<PostMeta> metas = Optional.ofNullable(postMetaListMap.get(post.getId()))
.orElseGet(LinkedList::new);
postListVO.setMetas(postMetaService.convertToMap(metas));
// Set comment count
postListVO.setCommentCount(commentCountMap.getOrDefault(post.getId(), 0L));
postListVO.setFullPath(buildFullPath(post));
return postListVO;
}).collect(Collectors.toList());
}
/**
* Converts to post detail vo.
*
* @param post post must not be null
* @param tags tags
* @param categories categories
* @param postMetaList postMetaList
* @return post detail vo
*/
@NonNull
public 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
PostDetailVO postDetailVO = new PostDetailVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postDetailVO);
// Extract ids
Set<Integer> tagIds = ServiceUtils.fetchProperty(tags, Tag::getId);
Set<Integer> categoryIds = ServiceUtils.fetchProperty(categories, Category::getId);
Set<Long> metaIds = ServiceUtils.fetchProperty(postMetaList, PostMeta::getId);
// Get post tag ids
postDetailVO.setTagIds(tagIds);
postDetailVO.setTags(tagService.convertTo(tags));
// Get post category ids
postDetailVO.setCategoryIds(categoryIds);
postDetailVO.setCategories(categoryService.convertTo(categories));
// Get post meta ids
postDetailVO.setMetaIds(metaIds);
postDetailVO.setMetas(postMetaService.convertTo(postMetaList));
postDetailVO.setCommentCount(postCommentService.countByStatusAndPostId(
CommentStatus.PUBLISHED, post.getId()));
postDetailVO.setFullPath(buildFullPath(post));
PatchedContent postContent = post.getContent();
postDetailVO.setContent(postContent.getContent());
postDetailVO.setOriginalContent(postContent.getOriginalContent());
// Post currently drafting in process
Boolean inProgress = contentService.draftingInProgress(post.getId());
postDetailVO.setInProgress(inProgress);
return postDetailVO;
}
/**
* Convert to year archives
*
* @param posts posts must not be null
* @return list of ArchiveYearVO
*/
public List<ArchiveYearVO> convertToYearArchives(List<Post> posts) {
Map<Integer, List<Post>> yearPostMap = new HashMap<>(8);
posts.forEach(post -> {
Calendar calendar = DateUtils.convertTo(post.getCreateTime());
yearPostMap.computeIfAbsent(calendar.get(Calendar.YEAR), year -> new LinkedList<>())
.add(post);
});
List<ArchiveYearVO> archives = new LinkedList<>();
yearPostMap.forEach((year, postList) -> {
// Build archive
ArchiveYearVO archive = new ArchiveYearVO();
archive.setYear(year);
archive.setPosts(convertToListVo(postList));
// Add archive
archives.add(archive);
});
// Sort this list
archives.sort(new ArchiveYearVO.ArchiveComparator());
return archives;
}
/**
* Convert to month archives
*
* @param posts posts must not be null
* @return list of ArchiveMonthVO
*/
public List<ArchiveMonthVO> convertToMonthArchives(List<Post> posts) {
Map<Integer, Map<Integer, List<Post>>> yearMonthPostMap = new HashMap<>(8);
posts.forEach(post -> {
Calendar calendar = DateUtils.convertTo(post.getCreateTime());
yearMonthPostMap.computeIfAbsent(calendar.get(Calendar.YEAR), year -> new HashMap<>())
.computeIfAbsent(calendar.get(Calendar.MONTH) + 1,
month -> new LinkedList<>())
.add(post);
});
List<ArchiveMonthVO> archives = new LinkedList<>();
yearMonthPostMap.forEach((year, monthPostMap) ->
monthPostMap.forEach((month, postList) -> {
ArchiveMonthVO archive = new ArchiveMonthVO();
archive.setYear(year);
archive.setMonth(month);
archive.setPosts(convertToListVo(postList));
archives.add(archive);
}));
// Sort this list
archives.sort(new ArchiveMonthVO.ArchiveComparator());
return archives;
}
/**
* Build post full path.
*
* @param post post
* @return full patch to access.
*/
public String buildFullPath(Post post) {
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
String pathSuffix = optionService.getPathSuffix();
String archivesPrefix = optionService.getArchivesPrefix();
int month = DateUtils.month(post.getCreateTime()) + 1;
String monthString = month < 10 ? "0" + month : String.valueOf(month);
int day = DateUtils.dayOfMonth(post.getCreateTime());
String dayString = day < 10 ? "0" + day : String.valueOf(day);
StringBuilder fullPath = new StringBuilder();
if (optionService.isEnabledAbsolutePath()) {
fullPath.append(optionService.getBlogBaseUrl());
}
fullPath.append(URL_SEPARATOR);
if (permalinkType.equals(PostPermalinkType.DEFAULT)) {
fullPath.append(archivesPrefix)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.ID)) {
fullPath.append("?p=")
.append(post.getId());
} else if (permalinkType.equals(PostPermalinkType.DATE)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(monthString)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.DAY)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(monthString)
.append(URL_SEPARATOR)
.append(dayString)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.YEAR)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.ID_SLUG)) {
fullPath.append(archivesPrefix)
.append(URL_SEPARATOR)
.append(post.getId())
.append(pathSuffix);
}
return fullPath.toString();
}
}

View File

@ -0,0 +1,82 @@
package run.halo.app.service.assembler;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Post;
import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.service.CategoryService;
import run.halo.app.service.ContentPatchLogService;
import run.halo.app.service.ContentService;
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.PostTagService;
import run.halo.app.service.TagService;
/**
* Post assembler for theme render.
*
* @author guqing
* @date 2022-03-01
*/
@Component
public class PostRenderAssembler extends PostAssembler {
private final ContentService contentService;
private final ContentPatchLogService contentPatchLogService;
public PostRenderAssembler(ContentService contentService,
OptionService optionService,
PostTagService postTagService,
PostCategoryService postCategoryService,
PostMetaService postMetaService,
PostCommentService postCommentService,
TagService tagService,
CategoryService categoryService,
ContentPatchLogService contentPatchLogService) {
super(contentService, optionService, postTagService, postCategoryService, postMetaService,
postCommentService, tagService, categoryService);
this.contentService = contentService;
this.contentPatchLogService = contentPatchLogService;
}
@Override
public Page<PostDetailVO> convertToDetailVo(Page<Post> postPage) {
Assert.notNull(postPage, "Post page must not be null");
// Populate post content
postPage.getContent().forEach(post -> {
Content postContent = contentService.getById(post.getId());
post.setContent(Content.PatchedContent.of(postContent));
});
return postPage.map(this::convertToDetailVo);
}
@Override
public PostDetailVO convertToDetailVo(Post post) {
Assert.notNull(post, "The post must not be null.");
post.setContent(PatchedContent.of(contentService.getById(post.getId())));
return super.convertToDetailVo(post);
}
/**
* Gets for preview.
*
* @param post post
* @return post detail with latest patched content.
*/
public PostDetailVO convertToPreviewDetailVo(Post post) {
Assert.notNull(post, "The post must not be null.");
post.setContent(getLatestContentBy(post.getId()));
return super.convertToDetailVo(post);
}
private PatchedContent getLatestContentBy(Integer postId) {
Content postContent = contentService.getById(postId);
// Use the head pointer stored in the post content.
return contentPatchLogService.getPatchedContentById(postContent.getHeadPatchLogId());
}
}

View File

@ -0,0 +1,185 @@
package run.halo.app.service.assembler;
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.data.domain.Page;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetMeta;
import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.enums.SheetPermalinkType;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.ContentService;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetMetaService;
import run.halo.app.utils.ServiceUtils;
/**
* Sheet assembler.
*
* @author guqing
* @date 2022-03-01
*/
@Component
public class SheetAssembler extends BasePostAssembler<Sheet> {
private final SheetCommentService sheetCommentService;
private final ContentService contentService;
private final SheetMetaService sheetMetaService;
private final OptionService optionService;
public SheetAssembler(SheetCommentService sheetCommentService,
ContentService contentService,
SheetMetaService sheetMetaService,
OptionService optionService) {
super(contentService, optionService);
this.sheetCommentService = sheetCommentService;
this.contentService = contentService;
this.sheetMetaService = sheetMetaService;
this.optionService = optionService;
}
/**
* Converts to list dto page.
*
* @param sheetPage sheet page must not be nulls
* @return a page of sheet list dto
*/
@NonNull
public Page<SheetListVO> convertToListVo(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);
// key: sheet id, value: comment count
Map<Integer, Long> sheetCommentCountMap = sheetCommentService.countByStatusAndPostIds(
CommentStatus.PUBLISHED, sheetIds);
return sheetPage.map(sheet -> {
SheetListVO sheetListVO = new SheetListVO().convertFrom(sheet);
sheetListVO.setCommentCount(sheetCommentCountMap.getOrDefault(sheet.getId(), 0L));
sheetListVO.setFullPath(buildFullPath(sheet));
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(sheet.getId());
sheetListVO.setInProgress(isInProcess);
return sheetListVO;
});
}
/**
* Converts to detail vo.
*
* @param sheet sheet must not be null
* @return sheet detail vo
*/
@NonNull
public SheetDetailVO convertToDetailVo(Sheet sheet) {
// List metas
List<SheetMeta> metas = sheetMetaService.listBy(sheet.getId());
// Convert to detail vo
return convertTo(sheet, metas);
}
@Override
public BasePostMinimalDTO convertToMinimal(Sheet sheet) {
Assert.notNull(sheet, "Sheet must not be null");
BasePostMinimalDTO basePostMinimalDTO = new BasePostMinimalDTO().convertFrom(sheet);
basePostMinimalDTO.setFullPath(buildFullPath(sheet));
return basePostMinimalDTO;
}
@Override
public List<BasePostMinimalDTO> convertToMinimal(List<Sheet> sheets) {
if (CollectionUtils.isEmpty(sheets)) {
return Collections.emptyList();
}
return sheets.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
@NonNull
public SheetDetailVO convertTo(@NonNull Sheet sheet, List<SheetMeta> metas) {
Assert.notNull(sheet, "Sheet must not be null");
// Convert to base detail vo
SheetDetailVO sheetDetailVO = new SheetDetailVO().convertFrom(sheet);
Set<Long> metaIds = ServiceUtils.fetchProperty(metas, SheetMeta::getId);
// Get sheet meta ids
sheetDetailVO.setMetaIds(metaIds);
sheetDetailVO.setMetas(sheetMetaService.convertTo(metas));
generateAndSetSummaryIfAbsent(sheet, sheetDetailVO);
sheetDetailVO.setCommentCount(sheetCommentService.countByStatusAndPostId(
CommentStatus.PUBLISHED, sheet.getId()));
sheetDetailVO.setFullPath(buildFullPath(sheet));
PatchedContent sheetContent = sheet.getContent();
sheetDetailVO.setContent(sheetContent.getContent());
sheetDetailVO.setOriginalContent(sheetContent.getOriginalContent());
// Sheet currently drafting in process
Boolean inProgress = contentService.draftingInProgress(sheet.getId());
sheetDetailVO.setInProgress(inProgress);
return sheetDetailVO;
}
/**
* Build sheet full path.
*
* @param sheet sheet
* @return a full path to access.
*/
private String buildFullPath(Sheet sheet) {
StringBuilder fullPath = new StringBuilder();
SheetPermalinkType permalinkType = optionService.getSheetPermalinkType();
if (optionService.isEnabledAbsolutePath()) {
fullPath.append(optionService.getBlogBaseUrl());
}
if (permalinkType.equals(SheetPermalinkType.SECONDARY)) {
fullPath.append(URL_SEPARATOR)
.append(optionService.getSheetPrefix())
.append(URL_SEPARATOR)
.append(sheet.getSlug())
.append(optionService.getPathSuffix());
} else if (permalinkType.equals(SheetPermalinkType.ROOT)) {
fullPath.append(URL_SEPARATOR)
.append(sheet.getSlug())
.append(optionService.getPathSuffix());
}
return fullPath.toString();
}
}

View File

@ -0,0 +1,68 @@
package run.halo.app.service.assembler;
import java.util.List;
import org.springframework.stereotype.Component;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetMeta;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.service.ContentPatchLogService;
import run.halo.app.service.ContentService;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetMetaService;
/**
* Sheet assembler for theme render.
*
* @author guqing
* @date 2022-03-01
*/
@Component
public class SheetRenderAssembler extends SheetAssembler {
private final SheetMetaService sheetMetaService;
private final ContentService contentService;
private final ContentPatchLogService contentPatchLogService;
public SheetRenderAssembler(SheetCommentService sheetCommentService,
ContentService contentService,
SheetMetaService sheetMetaService,
OptionService optionService,
ContentPatchLogService contentPatchLogService) {
super(sheetCommentService, contentService, sheetMetaService, optionService);
this.sheetMetaService = sheetMetaService;
this.contentService = contentService;
this.contentPatchLogService = contentPatchLogService;
}
@Override
public SheetDetailVO convertToDetailVo(Sheet sheet) {
sheet.setContent(Content.PatchedContent.of(contentService.getById(sheet.getId())));
// List metas
List<SheetMeta> metas = sheetMetaService.listBy(sheet.getId());
// Convert to detail vo
return super.convertTo(sheet, metas);
}
/**
* Gets sheet detail to preview.
*
* @param sheet sheet
* @return sheet detail with the latest patched content.
*/
public SheetDetailVO convertToPreviewDetailVo(Sheet sheet) {
sheet.setContent(getLatestContentBy(sheet.getId()));
// List metas
List<SheetMeta> metas = sheetMetaService.listBy(sheet.getId());
// Convert to detail vo
return super.convertTo(sheet, metas);
}
private PatchedContent getLatestContentBy(Integer postId) {
Content postContent = contentService.getById(postId);
// Use the head pointer stored in the post content.
return contentPatchLogService.getPatchedContentById(postContent.getHeadPatchLogId());
}
}

View File

@ -6,9 +6,6 @@ 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.post.BasePostDetailDTO;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.BasePost;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
@ -224,69 +221,6 @@ public interface BasePostService<POST extends BasePost> extends CrudService<POST
@NonNull
POST createOrUpdateBy(@NonNull POST post);
/**
* Convert POST to minimal dto.
*
* @param post post must not be null.
* @return minimal dto.
*/
@NonNull
BasePostMinimalDTO convertToMinimal(@NonNull POST post);
/**
* Convert list of POST to minimal dto of list.
*
* @param posts posts must not be null.
* @return a list of minimal dto.
*/
@NonNull
List<BasePostMinimalDTO> convertToMinimal(@Nullable List<POST> posts);
/**
* Convert page of POST to minimal dto of page.
*
* @param postPage postPage must not be null.
* @return a page of minimal dto.
*/
@NonNull
Page<BasePostMinimalDTO> convertToMinimal(@NonNull Page<POST> postPage);
/**
* Convert POST to simple dto.
*
* @param post post must not be null.
* @return simple dto.
*/
@NonNull
BasePostSimpleDTO convertToSimple(@NonNull POST post);
/**
* Convert list of POST to list of simple dto.
*
* @param posts posts must not be null.
* @return a list of simple dto.
*/
@NonNull
List<BasePostSimpleDTO> convertToSimple(@Nullable List<POST> posts);
/**
* Convert page of POST to page of simple dto.
*
* @param postPage postPage must not be null.
* @return a page of simple dto.
*/
@NonNull
Page<BasePostSimpleDTO> convertToSimple(@NonNull Page<POST> postPage);
/**
* Convert POST to detail dto.
*
* @param post post must not be null.
* @return detail dto.
*/
@NonNull
BasePostDetailDTO convertToDetail(@NonNull POST post);
/**
* Updates draft content.
*

View File

@ -24,8 +24,6 @@ import run.halo.app.exception.AlreadyExistsException;
import run.halo.app.exception.BadRequestException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.exception.ServiceException;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.BasePost;
import run.halo.app.model.entity.Content;
@ -303,7 +301,6 @@ public abstract class BasePostServiceImpl<POST extends BasePost>
PatchedContent postContent = post.getContent();
// word count stat
post.setWordCount(htmlFormatWordCount(postContent.getContent()));
post.setContent(postContent);
POST savedPost;
// Create or update post
@ -329,78 +326,6 @@ public abstract class BasePostServiceImpl<POST extends BasePost>
return savedPost;
}
@Override
public BasePostMinimalDTO convertToMinimal(POST post) {
Assert.notNull(post, "Post must not be null");
return new BasePostMinimalDTO().convertFrom(post);
}
@Override
public List<BasePostMinimalDTO> convertToMinimal(List<POST> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
@Override
public Page<BasePostMinimalDTO> convertToMinimal(Page<POST> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToMinimal);
}
@Override
public BasePostSimpleDTO convertToSimple(POST post) {
Assert.notNull(post, "Post must not be null");
BasePostSimpleDTO basePostSimpleDTO = new BasePostSimpleDTO().convertFrom(post);
// Set summary
generateAndSetSummaryIfAbsent(post, basePostSimpleDTO);
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(post.getId());
basePostSimpleDTO.setInProgress(isInProcess);
return basePostSimpleDTO;
}
@Override
public List<BasePostSimpleDTO> convertToSimple(List<POST> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToSimple)
.collect(Collectors.toList());
}
@Override
public Page<BasePostSimpleDTO> convertToSimple(Page<POST> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToSimple);
}
@Override
public BasePostDetailDTO convertToDetail(POST post) {
Assert.notNull(post, "Post must not be null");
BasePostDetailDTO postDetail = new BasePostDetailDTO().convertFrom(post);
// Post currently drafting in process
Boolean isInProcess = contentService.draftingInProgress(post.getId());
postDetail.setInProgress(isInProcess);
return postDetail;
}
@Override
@Transactional(rollbackFor = Exception.class)
public POST updateDraftContent(String content, String originalContent, Integer postId) {

View File

@ -1,18 +1,14 @@
package run.halo.app.service.impl;
import static org.springframework.data.domain.Sort.Direction.DESC;
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
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;
@ -29,7 +25,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@ -38,8 +33,6 @@ import run.halo.app.event.logger.LogEvent;
import run.halo.app.event.post.PostUpdatedEvent;
import run.halo.app.event.post.PostVisitEvent;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
@ -49,9 +42,7 @@ 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.CommentStatus;
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.PostParam;
import run.halo.app.model.params.PostQuery;
@ -59,7 +50,6 @@ import run.halo.app.model.properties.PostProperties;
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.model.vo.PostMarkdownVO;
import run.halo.app.repository.PostRepository;
import run.halo.app.repository.base.BasePostRepository;
@ -73,6 +63,7 @@ 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.service.assembler.PostAssembler;
import run.halo.app.utils.DateUtils;
import run.halo.app.utils.HaloUtils;
import run.halo.app.utils.MarkdownUtils;
@ -94,6 +85,8 @@ import run.halo.app.utils.SlugUtils;
@Service
public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostService {
private final PostAssembler postAssembler;
private final PostRepository postRepository;
private final TagService tagService;
@ -119,7 +112,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
private final ApplicationContext applicationContext;
public PostServiceImpl(BasePostRepository<Post> basePostRepository,
OptionService optionService,
PostAssembler postAssembler, OptionService optionService,
PostRepository postRepository,
TagService tagService,
CategoryService categoryService,
@ -132,6 +125,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
ContentPatchLogService contentPatchLogService,
ApplicationContext applicationContext) {
super(basePostRepository, optionService, contentService, contentPatchLogService);
this.postAssembler = postAssembler;
this.postRepository = postRepository;
this.tagService = tagService;
this.categoryService = categoryService;
@ -315,7 +309,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
List<Post> posts = postRepository
.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
return convertToYearArchives(posts);
return postAssembler.convertToYearArchives(posts);
}
@Override
@ -324,67 +318,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
List<Post> posts = postRepository
.findAllByStatus(PostStatus.PUBLISHED, Sort.by(DESC, "createTime"));
return convertToMonthArchives(posts);
}
@Override
public List<ArchiveYearVO> convertToYearArchives(List<Post> posts) {
Map<Integer, List<Post>> yearPostMap = new HashMap<>(8);
posts.forEach(post -> {
Calendar calendar = DateUtils.convertTo(post.getCreateTime());
yearPostMap.computeIfAbsent(calendar.get(Calendar.YEAR), year -> new LinkedList<>())
.add(post);
});
List<ArchiveYearVO> archives = new LinkedList<>();
yearPostMap.forEach((year, postList) -> {
// Build archive
ArchiveYearVO archive = new ArchiveYearVO();
archive.setYear(year);
archive.setPosts(convertToListVo(postList));
// Add archive
archives.add(archive);
});
// Sort this list
archives.sort(new ArchiveYearVO.ArchiveComparator());
return archives;
}
@Override
public List<ArchiveMonthVO> convertToMonthArchives(List<Post> posts) {
Map<Integer, Map<Integer, List<Post>>> yearMonthPostMap = new HashMap<>(8);
posts.forEach(post -> {
Calendar calendar = DateUtils.convertTo(post.getCreateTime());
yearMonthPostMap.computeIfAbsent(calendar.get(Calendar.YEAR), year -> new HashMap<>())
.computeIfAbsent(calendar.get(Calendar.MONTH) + 1,
month -> new LinkedList<>())
.add(post);
});
List<ArchiveMonthVO> archives = new LinkedList<>();
yearMonthPostMap.forEach((year, monthPostMap) ->
monthPostMap.forEach((month, postList) -> {
ArchiveMonthVO archive = new ArchiveMonthVO();
archive.setYear(year);
archive.setMonth(month);
archive.setPosts(convertToListVo(postList));
archives.add(archive);
}));
// Sort this list
archives.sort(new ArchiveMonthVO.ArchiveComparator());
return archives;
return postAssembler.convertToMonthArchives(posts);
}
@Override
@ -555,30 +489,6 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
return content.toString();
}
@Override
public PostDetailVO convertToDetailVo(Post post) {
return convertToDetailVo(post, false);
}
@Override
public PostDetailVO convertToDetailVo(Post post, boolean queryEncryptCategory) {
// List tags
List<Tag> tags = postTagService.listTagsBy(post.getId());
// List categories
List<Category> categories = postCategoryService
.listCategoriesBy(post.getId());
// List metas
List<PostMeta> metas = postMetaService.listBy(post.getId());
// Convert to detail vo
return convertTo(post, tags, categories, metas);
}
@Override
public Page<PostDetailVO> convertToDetailVo(Page<Post> postPage) {
Assert.notNull(postPage, "Post page must not be null");
return postPage.map(this::convertToDetailVo);
}
@Override
public Post removeById(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
@ -616,217 +526,6 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
return deletedPost;
}
@Override
public Page<PostListVO> convertToListVo(Page<Post> postPage) {
return convertToListVo(postPage, false);
}
@Override
public Page<PostListVO> convertToListVo(Page<Post> postPage, boolean queryEncryptCategory) {
Assert.notNull(postPage, "Post page must not be null");
List<Post> posts = postPage.getContent();
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
// Get tag list map
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
// Get category list map
Map<Integer, List<Category>> categoryListMap = postCategoryService
.listCategoryListMap(postIds);
// Get comment count
Map<Integer, Long> commentCountMap = postCommentService.countByStatusAndPostIds(
CommentStatus.PUBLISHED, postIds);
// Get post meta list map
Map<Integer, List<PostMeta>> postMetaListMap = postMetaService.listPostMetaAsMap(postIds);
return postPage.map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postListVO);
Optional.ofNullable(tagListMap.get(post.getId())).orElseGet(LinkedList::new);
// Set tags
postListVO.setTags(Optional.ofNullable(tagListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(tagService::convertTo)
.collect(Collectors.toList()));
// Set categories
postListVO.setCategories(Optional.ofNullable(categoryListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(categoryService::convertTo)
.collect(Collectors.toList()));
// Set post metas
List<PostMeta> metas = Optional.ofNullable(postMetaListMap.get(post.getId()))
.orElseGet(LinkedList::new);
postListVO.setMetas(postMetaService.convertToMap(metas));
// Set comment count
postListVO.setCommentCount(commentCountMap.getOrDefault(post.getId(), 0L));
postListVO.setFullPath(buildFullPath(post));
// Post currently drafting in process
Boolean isInProcess = postContentService.draftingInProgress(post.getId());
postListVO.setInProgress(isInProcess);
return postListVO;
});
}
@Override
public List<PostListVO> convertToListVo(List<Post> posts) {
Assert.notNull(posts, "Post page must not be null");
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
// Get tag list map
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
// Get category list map
Map<Integer, List<Category>> categoryListMap = postCategoryService
.listCategoryListMap(postIds);
// Get comment count
Map<Integer, Long> commentCountMap =
postCommentService.countByStatusAndPostIds(CommentStatus.PUBLISHED, postIds);
// Get post meta list map
Map<Integer, List<PostMeta>> postMetaListMap = postMetaService.listPostMetaAsMap(postIds);
return posts.stream().map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postListVO);
Optional.ofNullable(tagListMap.get(post.getId())).orElseGet(LinkedList::new);
// Set tags
postListVO.setTags(Optional.ofNullable(tagListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(tagService::convertTo)
.collect(Collectors.toList()));
// Set categories
postListVO.setCategories(Optional.ofNullable(categoryListMap.get(post.getId()))
.orElseGet(LinkedList::new)
.stream()
.filter(Objects::nonNull)
.map(categoryService::convertTo)
.collect(Collectors.toList()));
// Set post metas
List<PostMeta> metas = Optional.ofNullable(postMetaListMap.get(post.getId()))
.orElseGet(LinkedList::new);
postListVO.setMetas(postMetaService.convertToMap(metas));
// Set comment count
postListVO.setCommentCount(commentCountMap.getOrDefault(post.getId(), 0L));
postListVO.setFullPath(buildFullPath(post));
return postListVO;
}).collect(Collectors.toList());
}
@Override
public BasePostMinimalDTO convertToMinimal(Post post) {
Assert.notNull(post, "Post must not be null");
BasePostMinimalDTO basePostMinimalDTO = new BasePostMinimalDTO().convertFrom(post);
basePostMinimalDTO.setFullPath(buildFullPath(post));
return basePostMinimalDTO;
}
@Override
public List<BasePostMinimalDTO> convertToMinimal(List<Post> posts) {
if (CollectionUtils.isEmpty(posts)) {
return Collections.emptyList();
}
return posts.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
@Override
public BasePostSimpleDTO convertToSimple(Post post) {
Assert.notNull(post, "Post must not be null");
BasePostSimpleDTO basePostSimpleDTO = new BasePostSimpleDTO().convertFrom(post);
// Set summary
generateAndSetSummaryIfAbsent(post, basePostSimpleDTO);
basePostSimpleDTO.setFullPath(buildFullPath(post));
return basePostSimpleDTO;
}
/**
* Converts to post detail vo.
*
* @param post post must not be null
* @param tags tags
* @param categories categories
* @param postMetaList postMetaList
* @return post detail vo
*/
@NonNull
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
PostDetailVO postDetailVO = new PostDetailVO().convertFrom(post);
generateAndSetSummaryIfAbsent(post, postDetailVO);
// Extract ids
Set<Integer> tagIds = ServiceUtils.fetchProperty(tags, Tag::getId);
Set<Integer> categoryIds = ServiceUtils.fetchProperty(categories, Category::getId);
Set<Long> metaIds = ServiceUtils.fetchProperty(postMetaList, PostMeta::getId);
// Get post tag ids
postDetailVO.setTagIds(tagIds);
postDetailVO.setTags(tagService.convertTo(tags));
// Get post category ids
postDetailVO.setCategoryIds(categoryIds);
postDetailVO.setCategories(categoryService.convertTo(categories));
// Get post meta ids
postDetailVO.setMetaIds(metaIds);
postDetailVO.setMetas(postMetaService.convertTo(postMetaList));
postDetailVO.setCommentCount(postCommentService.countByStatusAndPostId(
CommentStatus.PUBLISHED, post.getId()));
postDetailVO.setFullPath(buildFullPath(post));
PatchedContent postContent = post.getContent();
postDetailVO.setContent(postContent.getContent());
postDetailVO.setOriginalContent(postContent.getOriginalContent());
// Post currently drafting in process
Boolean inProgress = postContentService.draftingInProgress(post.getId());
postDetailVO.setInProgress(inProgress);
return postDetailVO;
}
/**
* Build specification by post query.
*
@ -926,7 +625,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
post.setContent(
postContentPatchLogService.getPatchedContentById(postContent.getHeadPatchLogId()));
// Convert to post detail vo
return convertTo(post, tags, categories, postMetaList);
return postAssembler.convertTo(post, tags, categories, postMetaList);
}
@Override
@ -960,7 +659,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
frontMatter.append("updated: ").append(post.getUpdateTime()).append("\n");
//set fullPath
frontMatter.append("url: ").append(buildFullPath(post)).append("\n");
frontMatter.append("url: ").append(postAssembler.buildFullPath(post)).append("\n");
//set category
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
@ -998,66 +697,4 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
postMarkdownVO.setSlug(post.getSlug());
return postMarkdownVO;
}
private String buildFullPath(Post post) {
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
String pathSuffix = optionService.getPathSuffix();
String archivesPrefix = optionService.getArchivesPrefix();
int month = DateUtils.month(post.getCreateTime()) + 1;
String monthString = month < 10 ? "0" + month : String.valueOf(month);
int day = DateUtils.dayOfMonth(post.getCreateTime());
String dayString = day < 10 ? "0" + day : String.valueOf(day);
StringBuilder fullPath = new StringBuilder();
if (optionService.isEnabledAbsolutePath()) {
fullPath.append(optionService.getBlogBaseUrl());
}
fullPath.append(URL_SEPARATOR);
if (permalinkType.equals(PostPermalinkType.DEFAULT)) {
fullPath.append(archivesPrefix)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.ID)) {
fullPath.append("?p=")
.append(post.getId());
} else if (permalinkType.equals(PostPermalinkType.DATE)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(monthString)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.DAY)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(monthString)
.append(URL_SEPARATOR)
.append(dayString)
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.YEAR)) {
fullPath.append(DateUtils.year(post.getCreateTime()))
.append(URL_SEPARATOR)
.append(post.getSlug())
.append(pathSuffix);
} else if (permalinkType.equals(PostPermalinkType.ID_SLUG)) {
fullPath.append(archivesPrefix)
.append(URL_SEPARATOR)
.append(post.getId())
.append(pathSuffix);
}
return fullPath.toString();
}
}

View File

@ -1,39 +1,28 @@
package run.halo.app.service.impl;
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import run.halo.app.event.logger.LogEvent;
import run.halo.app.event.post.SheetVisitEvent;
import run.halo.app.exception.AlreadyExistsException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.dto.IndependentSheetDTO;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.entity.Content;
import run.halo.app.model.entity.Content.PatchedContent;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.SheetComment;
import run.halo.app.model.entity.SheetMeta;
import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.enums.LogType;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.enums.SheetPermalinkType;
import run.halo.app.model.vo.SheetDetailVO;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.repository.SheetRepository;
import run.halo.app.service.ContentPatchLogService;
import run.halo.app.service.ContentService;
@ -294,98 +283,11 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet>
return sheet;
}
@Override
public Page<SheetListVO> convertToListVo(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);
// key: sheet id, value: comment count
Map<Integer, Long> sheetCommentCountMap = sheetCommentService.countByStatusAndPostIds(
CommentStatus.PUBLISHED, sheetIds);
return sheetPage.map(sheet -> {
SheetListVO sheetListVO = new SheetListVO().convertFrom(sheet);
sheetListVO.setCommentCount(sheetCommentCountMap.getOrDefault(sheet.getId(), 0L));
sheetListVO.setFullPath(buildFullPath(sheet));
// Post currently drafting in process
Boolean isInProcess = sheetContentService.draftingInProgress(sheet.getId());
sheetListVO.setInProgress(isInProcess);
return sheetListVO;
});
}
@Override
public void publishVisitEvent(Integer sheetId) {
eventPublisher.publishEvent(new SheetVisitEvent(this, sheetId));
}
@Override
public SheetDetailVO convertToDetailVo(Sheet sheet) {
// List metas
List<SheetMeta> metas = sheetMetaService.listBy(sheet.getId());
// Convert to detail vo
return convertTo(sheet, metas);
}
@Override
public BasePostMinimalDTO convertToMinimal(Sheet sheet) {
Assert.notNull(sheet, "Sheet must not be null");
BasePostMinimalDTO basePostMinimalDTO = new BasePostMinimalDTO().convertFrom(sheet);
basePostMinimalDTO.setFullPath(buildFullPath(sheet));
return basePostMinimalDTO;
}
@Override
public List<BasePostMinimalDTO> convertToMinimal(List<Sheet> sheets) {
if (CollectionUtils.isEmpty(sheets)) {
return Collections.emptyList();
}
return sheets.stream()
.map(this::convertToMinimal)
.collect(Collectors.toList());
}
@NonNull
private SheetDetailVO convertTo(@NonNull Sheet sheet, List<SheetMeta> metas) {
Assert.notNull(sheet, "Sheet must not be null");
// Convert to base detail vo
SheetDetailVO sheetDetailVO = new SheetDetailVO().convertFrom(sheet);
Set<Long> metaIds = ServiceUtils.fetchProperty(metas, SheetMeta::getId);
// Get sheet meta ids
sheetDetailVO.setMetaIds(metaIds);
sheetDetailVO.setMetas(sheetMetaService.convertTo(metas));
generateAndSetSummaryIfAbsent(sheet, sheetDetailVO);
sheetDetailVO.setCommentCount(sheetCommentService.countByStatusAndPostId(
CommentStatus.PUBLISHED, sheet.getId()));
sheetDetailVO.setFullPath(buildFullPath(sheet));
PatchedContent sheetContent = sheet.getContent();
sheetDetailVO.setContent(sheetContent.getContent());
sheetDetailVO.setOriginalContent(sheetContent.getOriginalContent());
// Sheet currently drafting in process
Boolean inProgress = sheetContentService.draftingInProgress(sheet.getId());
sheetDetailVO.setInProgress(inProgress);
return sheetDetailVO;
}
@Override
protected void slugMustNotExist(Sheet sheet) {
Assert.notNull(sheet, "Sheet must not be null");
@ -405,29 +307,4 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet>
throw new AlreadyExistsException("页面别名 " + sheet.getSlug() + " 已存在");
}
}
private String buildFullPath(Sheet sheet) {
StringBuilder fullPath = new StringBuilder();
SheetPermalinkType permalinkType = optionService.getSheetPermalinkType();
if (optionService.isEnabledAbsolutePath()) {
fullPath.append(optionService.getBlogBaseUrl());
}
if (permalinkType.equals(SheetPermalinkType.SECONDARY)) {
fullPath.append(URL_SEPARATOR)
.append(optionService.getSheetPrefix())
.append(URL_SEPARATOR)
.append(sheet.getSlug())
.append(optionService.getPathSuffix());
} else if (permalinkType.equals(SheetPermalinkType.ROOT)) {
fullPath.append(URL_SEPARATOR)
.append(sheet.getSlug())
.append(optionService.getPathSuffix());
}
return fullPath.toString();
}
}

View File

@ -1,15 +1,22 @@
package run.halo.app.service.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import run.halo.app.model.entity.Category;
import run.halo.app.model.vo.CategoryVO;
import run.halo.app.repository.CategoryRepository;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.utils.JsonUtils;
/**
@ -18,13 +25,35 @@ import run.halo.app.utils.JsonUtils;
* @author guqing
* @date 2021-12-04
*/
@ActiveProfiles("test")
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class CategoryServiceTest {
@Autowired
private ApplicationContext applicationContext;
@MockBean
private CategoryRepository categoryRepository;
@MockBean
private PostCategoryService postCategoryService;
@MockBean
private OptionService optionService;
private CategoryServiceImpl categoryService;
@BeforeEach
public void setUp() {
categoryService =
new CategoryServiceImpl(categoryRepository, postCategoryService, optionService,
applicationContext);
when(optionService.isEnabledAbsolutePath()).thenReturn(true);
when(optionService.getBlogBaseUrl()).thenReturn("http://127.0.0.1:8090");
when(optionService.getCategoriesPrefix()).thenReturn("categories");
when(optionService.getPathSuffix()).thenReturn("");
}
@Test
void listToTree() throws JsonProcessingException {
List<Category> categories = mockCategories();