mirror of https://github.com/halo-dev/halo
* feat: #1225 * fix: compatible with jdk1.8 * fix: format code * fix: fix the problem that the status of the recycle bin file is incorrect when revocering * fix: format code * fix: format code * fix: fix the post cannot be converted to recyling mode * fix: post cannot be published on deleting the category password * fix: fix jpa error * fix: format code * fix: encryption type extracted into enum * fix: format code * fix: format code * fix: changes requested * fix: format code * fix: revert checkstyle.xml * fix: change request * fix: not encrypt 方法改为重载方法 * fix: 修复因调整 git 版本被回退的代码 Co-authored-by: xiangbei.yzx <xiangbei.yzx@alibaba-inc.com>pull/1256/head
parent
f28d833fa8
commit
7b88fcab5f
|
@ -51,8 +51,8 @@ public class AdminController {
|
||||||
@GetMapping(value = "/is_installed")
|
@GetMapping(value = "/is_installed")
|
||||||
@ApiOperation("Checks Installation status")
|
@ApiOperation("Checks Installation status")
|
||||||
public boolean isInstall() {
|
public boolean isInstall() {
|
||||||
return optionService
|
return optionService.getByPropertyOrDefault(PrimaryProperties.IS_INSTALLED, Boolean.class,
|
||||||
.getByPropertyOrDefault(PrimaryProperties.IS_INSTALLED, Boolean.class, false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("login/precheck")
|
@PostMapping("login/precheck")
|
||||||
|
|
|
@ -56,10 +56,10 @@ public class CategoryController {
|
||||||
@SortDefault(sort = "createTime", direction = DESC) Sort sort,
|
@SortDefault(sort = "createTime", direction = DESC) Sort sort,
|
||||||
@RequestParam(name = "more", required = false, defaultValue = "false") boolean more) {
|
@RequestParam(name = "more", required = false, defaultValue = "false") boolean more) {
|
||||||
if (more) {
|
if (more) {
|
||||||
return postCategoryService.listCategoryWithPostCountDto(sort);
|
return postCategoryService.listCategoryWithPostCountDto(sort, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return categoryService.convertTo(categoryService.listAll(sort));
|
return categoryService.convertTo(categoryService.listAll(sort, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("tree_view")
|
@GetMapping("tree_view")
|
||||||
|
@ -81,7 +81,8 @@ public class CategoryController {
|
||||||
@PutMapping("{categoryId:\\d+}")
|
@PutMapping("{categoryId:\\d+}")
|
||||||
@ApiOperation("Updates category")
|
@ApiOperation("Updates category")
|
||||||
public CategoryDTO updateBy(@PathVariable("categoryId") Integer categoryId,
|
public CategoryDTO updateBy(@PathVariable("categoryId") Integer categoryId,
|
||||||
@RequestBody @Valid CategoryParam categoryParam) {
|
@RequestBody @Valid CategoryParam categoryParam
|
||||||
|
) {
|
||||||
Category categoryToUpdate = categoryService.getById(categoryId);
|
Category categoryToUpdate = categoryService.getById(categoryId);
|
||||||
categoryParam.update(categoryToUpdate);
|
categoryParam.update(categoryToUpdate);
|
||||||
return categoryService.convertTo(categoryService.update(categoryToUpdate));
|
return categoryService.convertTo(categoryService.update(categoryToUpdate));
|
||||||
|
|
|
@ -35,8 +35,8 @@ public class MigrateController {
|
||||||
@PostMapping("halo")
|
@PostMapping("halo")
|
||||||
@ApiOperation("Migrate from Halo")
|
@ApiOperation("Migrate from Halo")
|
||||||
public void migrateHalo(@RequestPart("file") MultipartFile file) {
|
public void migrateHalo(@RequestPart("file") MultipartFile file) {
|
||||||
if (optionService
|
if (optionService.getByPropertyOrDefault(
|
||||||
.getByPropertyOrDefault(PrimaryProperties.IS_INSTALLED, Boolean.class, false)) {
|
PrimaryProperties.IS_INSTALLED, Boolean.class, false)) {
|
||||||
throw new BadRequestException("无法在博客初始化完成之后迁移数据");
|
throw new BadRequestException("无法在博客初始化完成之后迁移数据");
|
||||||
}
|
}
|
||||||
migrateService.migrate(file, MigrateType.HALO);
|
migrateService.migrate(file, MigrateType.HALO);
|
||||||
|
|
|
@ -2,13 +2,11 @@ package run.halo.app.controller.admin.api;
|
||||||
|
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
@ -22,12 +20,10 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import run.halo.app.cache.AbstractStringCacheStore;
|
|
||||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||||
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
||||||
import run.halo.app.model.dto.post.BasePostSimpleDTO;
|
import run.halo.app.model.dto.post.BasePostSimpleDTO;
|
||||||
import run.halo.app.model.entity.Post;
|
import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.enums.PostPermalinkType;
|
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.params.PostContentParam;
|
import run.halo.app.model.params.PostContentParam;
|
||||||
import run.halo.app.model.params.PostParam;
|
import run.halo.app.model.params.PostParam;
|
||||||
|
@ -50,15 +46,12 @@ public class PostController {
|
||||||
|
|
||||||
private final PostService postService;
|
private final PostService postService;
|
||||||
|
|
||||||
private final AbstractStringCacheStore cacheStore;
|
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
|
||||||
public PostController(PostService postService,
|
public PostController(PostService postService,
|
||||||
AbstractStringCacheStore cacheStore,
|
|
||||||
OptionService optionService) {
|
OptionService optionService) {
|
||||||
this.postService = postService;
|
this.postService = postService;
|
||||||
this.cacheStore = cacheStore;
|
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +63,7 @@ public class PostController {
|
||||||
@RequestParam(value = "more", defaultValue = "true") Boolean more) {
|
@RequestParam(value = "more", defaultValue = "true") Boolean more) {
|
||||||
Page<Post> postPage = postService.pageBy(postQuery, pageable);
|
Page<Post> postPage = postService.pageBy(postQuery, pageable);
|
||||||
if (more) {
|
if (more) {
|
||||||
return postService.convertToListVo(postPage);
|
return postService.convertToListVo(postPage, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return postService.convertToSimple(postPage);
|
return postService.convertToSimple(postPage);
|
||||||
|
@ -92,7 +85,7 @@ public class PostController {
|
||||||
Page<Post> posts = postService.pageBy(status, pageable);
|
Page<Post> posts = postService.pageBy(status, pageable);
|
||||||
|
|
||||||
if (more) {
|
if (more) {
|
||||||
return postService.convertToListVo(posts);
|
return postService.convertToListVo(posts, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return postService.convertToSimple(posts);
|
return postService.convertToSimple(posts);
|
||||||
|
@ -102,7 +95,7 @@ public class PostController {
|
||||||
@ApiOperation("Gets a post")
|
@ApiOperation("Gets a post")
|
||||||
public PostDetailVO getBy(@PathVariable("postId") Integer postId) {
|
public PostDetailVO getBy(@PathVariable("postId") Integer postId) {
|
||||||
Post post = postService.getById(postId);
|
Post post = postService.getById(postId);
|
||||||
return postService.convertToDetailVo(post);
|
return postService.convertToDetailVo(post, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("{postId:\\d+}/likes")
|
@PutMapping("{postId:\\d+}/likes")
|
||||||
|
@ -114,8 +107,8 @@ public class PostController {
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@ApiOperation("Creates a post")
|
@ApiOperation("Creates a post")
|
||||||
public PostDetailVO createBy(@Valid @RequestBody PostParam postParam,
|
public PostDetailVO createBy(@Valid @RequestBody PostParam postParam,
|
||||||
@RequestParam(value = "autoSave", required = false, defaultValue = "false")
|
@RequestParam(value = "autoSave", required = false, defaultValue = "false") Boolean autoSave
|
||||||
Boolean autoSave) {
|
) {
|
||||||
// Convert to
|
// Convert to
|
||||||
Post post = postParam.convertTo();
|
Post post = postParam.convertTo();
|
||||||
return postService.createBy(post, postParam.getTagIds(), postParam.getCategoryIds(),
|
return postService.createBy(post, postParam.getTagIds(), postParam.getCategoryIds(),
|
||||||
|
@ -126,8 +119,8 @@ public class PostController {
|
||||||
@ApiOperation("Updates a post")
|
@ApiOperation("Updates a post")
|
||||||
public PostDetailVO updateBy(@Valid @RequestBody PostParam postParam,
|
public PostDetailVO updateBy(@Valid @RequestBody PostParam postParam,
|
||||||
@PathVariable("postId") Integer postId,
|
@PathVariable("postId") Integer postId,
|
||||||
@RequestParam(value = "autoSave", required = false, defaultValue = "false")
|
@RequestParam(value = "autoSave", required = false, defaultValue = "false") Boolean autoSave
|
||||||
Boolean autoSave) {
|
) {
|
||||||
// Get the post info
|
// Get the post info
|
||||||
Post postToUpdate = postService.getById(postId);
|
Post postToUpdate = postService.getById(postId);
|
||||||
|
|
||||||
|
@ -186,11 +179,6 @@ public class PostController {
|
||||||
|
|
||||||
BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post);
|
BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post);
|
||||||
|
|
||||||
String token = IdUtil.simpleUUID();
|
|
||||||
|
|
||||||
// cache preview token
|
|
||||||
cacheStore.putAny(token, token, 10, TimeUnit.MINUTES);
|
|
||||||
|
|
||||||
StringBuilder previewUrl = new StringBuilder();
|
StringBuilder previewUrl = new StringBuilder();
|
||||||
|
|
||||||
if (!optionService.isEnabledAbsolutePath()) {
|
if (!optionService.isEnabledAbsolutePath()) {
|
||||||
|
@ -199,14 +187,6 @@ public class PostController {
|
||||||
|
|
||||||
previewUrl.append(postMinimalDTO.getFullPath());
|
previewUrl.append(postMinimalDTO.getFullPath());
|
||||||
|
|
||||||
if (optionService.getPostPermalinkType().equals(PostPermalinkType.ID)) {
|
|
||||||
previewUrl.append("&token=")
|
|
||||||
.append(token);
|
|
||||||
} else {
|
|
||||||
previewUrl.append("?token=")
|
|
||||||
.append(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
// build preview post url and return
|
// build preview post url and return
|
||||||
return previewUrl.toString();
|
return previewUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package run.halo.app.controller.content;
|
package run.halo.app.controller.content;
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -24,12 +22,17 @@ import run.halo.app.controller.content.model.PostModel;
|
||||||
import run.halo.app.controller.content.model.SheetModel;
|
import run.halo.app.controller.content.model.SheetModel;
|
||||||
import run.halo.app.controller.content.model.TagModel;
|
import run.halo.app.controller.content.model.TagModel;
|
||||||
import run.halo.app.exception.NotFoundException;
|
import run.halo.app.exception.NotFoundException;
|
||||||
|
import run.halo.app.exception.UnsupportedException;
|
||||||
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
||||||
|
import run.halo.app.model.entity.Category;
|
||||||
import run.halo.app.model.entity.Post;
|
import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.entity.Sheet;
|
import run.halo.app.model.entity.Sheet;
|
||||||
|
import run.halo.app.model.enums.EncryptTypeEnum;
|
||||||
import run.halo.app.model.enums.PostPermalinkType;
|
import run.halo.app.model.enums.PostPermalinkType;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.enums.SheetPermalinkType;
|
import run.halo.app.model.enums.SheetPermalinkType;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostService;
|
import run.halo.app.service.PostService;
|
||||||
import run.halo.app.service.SheetService;
|
import run.halo.app.service.SheetService;
|
||||||
|
@ -65,6 +68,10 @@ public class ContentContentController {
|
||||||
|
|
||||||
private final AbstractStringCacheStore cacheStore;
|
private final AbstractStringCacheStore cacheStore;
|
||||||
|
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
private final CategoryService categoryService;
|
||||||
|
|
||||||
public ContentContentController(PostModel postModel,
|
public ContentContentController(PostModel postModel,
|
||||||
SheetModel sheetModel,
|
SheetModel sheetModel,
|
||||||
CategoryModel categoryModel,
|
CategoryModel categoryModel,
|
||||||
|
@ -75,7 +82,9 @@ public class ContentContentController {
|
||||||
OptionService optionService,
|
OptionService optionService,
|
||||||
PostService postService,
|
PostService postService,
|
||||||
SheetService sheetService,
|
SheetService sheetService,
|
||||||
AbstractStringCacheStore cacheStore) {
|
AbstractStringCacheStore cacheStore,
|
||||||
|
AuthenticationService authenticationService,
|
||||||
|
CategoryService categoryService) {
|
||||||
this.postModel = postModel;
|
this.postModel = postModel;
|
||||||
this.sheetModel = sheetModel;
|
this.sheetModel = sheetModel;
|
||||||
this.categoryModel = categoryModel;
|
this.categoryModel = categoryModel;
|
||||||
|
@ -87,6 +96,8 @@ public class ContentContentController {
|
||||||
this.postService = postService;
|
this.postService = postService;
|
||||||
this.sheetService = sheetService;
|
this.sheetService = sheetService;
|
||||||
this.cacheStore = cacheStore;
|
this.cacheStore = cacheStore;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
|
this.categoryService = categoryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("{prefix}")
|
@GetMapping("{prefix}")
|
||||||
|
@ -225,14 +236,32 @@ public class ContentContentController {
|
||||||
throw new NotFoundException("Not Found");
|
throw new NotFoundException("Not Found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "archives/{slug:.*}/password")
|
@PostMapping(value = "archives/{type}/{slug:.*}/password")
|
||||||
@CacheLock(traceRequest = true, expired = 2)
|
@CacheLock(traceRequest = true, expired = 2)
|
||||||
public String password(@PathVariable("slug") String slug,
|
public String password(@PathVariable("type") String type,
|
||||||
|
@PathVariable("slug") String slug,
|
||||||
@RequestParam(value = "password") String password) throws UnsupportedEncodingException {
|
@RequestParam(value = "password") String password) throws UnsupportedEncodingException {
|
||||||
|
|
||||||
|
String redirectUrl;
|
||||||
|
|
||||||
|
if (EncryptTypeEnum.POST.getName().equals(type)) {
|
||||||
|
redirectUrl = doAuthenticationPost(slug, password);
|
||||||
|
} else if (EncryptTypeEnum.CATEGORY.getName().equals(type)) {
|
||||||
|
redirectUrl = doAuthenticationCategory(slug, password);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedException("未知的加密类型");
|
||||||
|
}
|
||||||
|
return "redirect:" + redirectUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doAuthenticationPost(
|
||||||
|
String slug, String password) throws UnsupportedEncodingException {
|
||||||
Post post = postService.getBy(PostStatus.INTIMATE, slug);
|
Post post = postService.getBy(PostStatus.INTIMATE, slug);
|
||||||
|
|
||||||
post.setSlug(URLEncoder.encode(post.getSlug(), StandardCharsets.UTF_8.name()));
|
post.setSlug(URLEncoder.encode(post.getSlug(), StandardCharsets.UTF_8.name()));
|
||||||
|
|
||||||
|
authenticationService.postAuthentication(post, password);
|
||||||
|
|
||||||
BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post);
|
BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post);
|
||||||
|
|
||||||
StringBuilder redirectUrl = new StringBuilder();
|
StringBuilder redirectUrl = new StringBuilder();
|
||||||
|
@ -243,19 +272,22 @@ public class ContentContentController {
|
||||||
|
|
||||||
redirectUrl.append(postMinimalDTO.getFullPath());
|
redirectUrl.append(postMinimalDTO.getFullPath());
|
||||||
|
|
||||||
if (password.equals(post.getPassword())) {
|
return redirectUrl.toString();
|
||||||
String token = IdUtil.simpleUUID();
|
}
|
||||||
cacheStore.putAny(token, token, 10, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
if (optionService.getPostPermalinkType().equals(PostPermalinkType.ID)) {
|
private String doAuthenticationCategory(String slug, String password) {
|
||||||
redirectUrl.append("&token=")
|
Category category = categoryService.getBySlugOfNonNull(slug, true);
|
||||||
.append(token);
|
|
||||||
} else {
|
authenticationService.categoryAuthentication(category.getId(), password);
|
||||||
redirectUrl.append("?token=")
|
|
||||||
.append(token);
|
StringBuilder redirectUrl = new StringBuilder();
|
||||||
}
|
|
||||||
|
if (!optionService.isEnabledAbsolutePath()) {
|
||||||
|
redirectUrl.append(optionService.getBlogBaseUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
return "redirect:" + redirectUrl;
|
redirectUrl.append(optionService.getCategoriesPrefix()).append(slug);
|
||||||
|
|
||||||
|
return redirectUrl.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package run.halo.app.controller.content.api;
|
||||||
|
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
@ -14,11 +15,13 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import run.halo.app.exception.ForbiddenException;
|
||||||
import run.halo.app.model.dto.CategoryDTO;
|
import run.halo.app.model.dto.CategoryDTO;
|
||||||
import run.halo.app.model.entity.Category;
|
import run.halo.app.model.entity.Category;
|
||||||
import run.halo.app.model.entity.Post;
|
import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.vo.PostListVO;
|
import run.halo.app.model.vo.PostListVO;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
import run.halo.app.service.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
import run.halo.app.service.PostService;
|
import run.halo.app.service.PostService;
|
||||||
|
@ -39,12 +42,16 @@ public class CategoryController {
|
||||||
|
|
||||||
private final PostService postService;
|
private final PostService postService;
|
||||||
|
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
|
||||||
public CategoryController(CategoryService categoryService,
|
public CategoryController(CategoryService categoryService,
|
||||||
PostCategoryService postCategoryService,
|
PostCategoryService postCategoryService,
|
||||||
PostService postService) {
|
PostService postService,
|
||||||
|
AuthenticationService authenticationService) {
|
||||||
this.categoryService = categoryService;
|
this.categoryService = categoryService;
|
||||||
this.postCategoryService = postCategoryService;
|
this.postCategoryService = postCategoryService;
|
||||||
this.postService = postService;
|
this.postService = postService;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
|
@ -53,7 +60,7 @@ public class CategoryController {
|
||||||
@SortDefault(sort = "updateTime", direction = DESC) Sort sort,
|
@SortDefault(sort = "updateTime", direction = DESC) Sort sort,
|
||||||
@RequestParam(name = "more", required = false, defaultValue = "false") Boolean more) {
|
@RequestParam(name = "more", required = false, defaultValue = "false") Boolean more) {
|
||||||
if (more) {
|
if (more) {
|
||||||
return postCategoryService.listCategoryWithPostCountDto(sort);
|
return postCategoryService.listCategoryWithPostCountDto(sort, false);
|
||||||
}
|
}
|
||||||
return categoryService.convertTo(categoryService.listAll(sort));
|
return categoryService.convertTo(categoryService.listAll(sort));
|
||||||
}
|
}
|
||||||
|
@ -61,13 +68,19 @@ public class CategoryController {
|
||||||
@GetMapping("{slug}/posts")
|
@GetMapping("{slug}/posts")
|
||||||
@ApiOperation("Lists posts by category slug")
|
@ApiOperation("Lists posts by category slug")
|
||||||
public Page<PostListVO> listPostsBy(@PathVariable("slug") String slug,
|
public Page<PostListVO> listPostsBy(@PathVariable("slug") String slug,
|
||||||
|
@RequestParam(value = "password", required = false) String password,
|
||||||
@PageableDefault(sort = {"topPriority", "updateTime"}, direction = DESC)
|
@PageableDefault(sort = {"topPriority", "updateTime"}, direction = DESC)
|
||||||
Pageable pageable) {
|
Pageable pageable) {
|
||||||
// Get category by slug
|
// Get category by slug
|
||||||
Category category = categoryService.getBySlugOfNonNull(slug);
|
Category category = categoryService.getBySlugOfNonNull(slug, true);
|
||||||
|
|
||||||
|
if (!authenticationService.categoryAuthentication(category.getId(), password)) {
|
||||||
|
throw new ForbiddenException("您没有该分类的访问权限");
|
||||||
|
}
|
||||||
|
|
||||||
Page<Post> postPage =
|
Page<Post> postPage =
|
||||||
postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable);
|
postCategoryService.pagePostBy(category.getId(),
|
||||||
|
Sets.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE), pageable);
|
||||||
return postService.convertToListVo(postPage);
|
return postService.convertToListVo(postPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package run.halo.app.controller.content.model;
|
package run.halo.app.controller.content.model;
|
||||||
|
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
|
import static run.halo.app.model.support.HaloConst.POST_PASSWORD_TEMPLATE;
|
||||||
|
import static run.halo.app.model.support.HaloConst.SUFFIX_FTL;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
@ -12,8 +15,10 @@ import org.springframework.ui.Model;
|
||||||
import run.halo.app.model.dto.CategoryDTO;
|
import run.halo.app.model.dto.CategoryDTO;
|
||||||
import run.halo.app.model.entity.Category;
|
import run.halo.app.model.entity.Category;
|
||||||
import run.halo.app.model.entity.Post;
|
import run.halo.app.model.entity.Post;
|
||||||
|
import run.halo.app.model.enums.EncryptTypeEnum;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.vo.PostListVO;
|
import run.halo.app.model.vo.PostListVO;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
import run.halo.app.service.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
|
@ -39,14 +44,20 @@ public class CategoryModel {
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
public CategoryModel(CategoryService categoryService, ThemeService themeService,
|
private final AuthenticationService authenticationService;
|
||||||
PostCategoryService postCategoryService, PostService postService,
|
|
||||||
OptionService optionService) {
|
public CategoryModel(CategoryService categoryService,
|
||||||
|
ThemeService themeService,
|
||||||
|
PostCategoryService postCategoryService,
|
||||||
|
PostService postService,
|
||||||
|
OptionService optionService,
|
||||||
|
AuthenticationService authenticationService) {
|
||||||
this.categoryService = categoryService;
|
this.categoryService = categoryService;
|
||||||
this.themeService = themeService;
|
this.themeService = themeService;
|
||||||
this.postCategoryService = postCategoryService;
|
this.postCategoryService = postCategoryService;
|
||||||
this.postService = postService;
|
this.postService = postService;
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,15 +82,27 @@ public class CategoryModel {
|
||||||
* @return template name
|
* @return template name
|
||||||
*/
|
*/
|
||||||
public String listPost(Model model, String slug, Integer page) {
|
public String listPost(Model model, String slug, Integer page) {
|
||||||
|
|
||||||
// Get category by slug
|
// Get category by slug
|
||||||
final Category category = categoryService.getBySlugOfNonNull(slug);
|
final Category category = categoryService.getBySlugOfNonNull(slug, true);
|
||||||
|
|
||||||
|
if (!authenticationService.categoryAuthentication(category.getId(), null)) {
|
||||||
|
model.addAttribute("slug", category.getSlug());
|
||||||
|
model.addAttribute("type", EncryptTypeEnum.CATEGORY.getName());
|
||||||
|
if (themeService.templateExists(POST_PASSWORD_TEMPLATE + SUFFIX_FTL)) {
|
||||||
|
return themeService.render(POST_PASSWORD_TEMPLATE);
|
||||||
|
}
|
||||||
|
return "common/template/" + POST_PASSWORD_TEMPLATE;
|
||||||
|
}
|
||||||
|
|
||||||
CategoryDTO categoryDTO = categoryService.convertTo(category);
|
CategoryDTO categoryDTO = categoryService.convertTo(category);
|
||||||
|
|
||||||
final Pageable pageable = PageRequest.of(page - 1,
|
final Pageable pageable = PageRequest.of(page - 1,
|
||||||
optionService.getArchivesPageSize(),
|
optionService.getArchivesPageSize(),
|
||||||
Sort.by(DESC, "topPriority", "createTime"));
|
Sort.by(DESC, "topPriority", "createTime"));
|
||||||
Page<Post> postPage =
|
Page<Post> postPage =
|
||||||
postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable);
|
postCategoryService.pagePostBy(category.getId(), Sets
|
||||||
|
.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE), pageable);
|
||||||
Page<PostListVO> posts = postService.convertToListVo(postPage);
|
Page<PostListVO> posts = postService.convertToListVo(postPage);
|
||||||
|
|
||||||
// Generate meta description.
|
// Generate meta description.
|
||||||
|
|
|
@ -13,15 +13,16 @@ import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import run.halo.app.cache.AbstractStringCacheStore;
|
import run.halo.app.cache.AbstractStringCacheStore;
|
||||||
import run.halo.app.exception.ForbiddenException;
|
|
||||||
import run.halo.app.model.entity.Category;
|
import run.halo.app.model.entity.Category;
|
||||||
import run.halo.app.model.entity.Post;
|
import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.entity.PostMeta;
|
import run.halo.app.model.entity.PostMeta;
|
||||||
import run.halo.app.model.entity.Tag;
|
import run.halo.app.model.entity.Tag;
|
||||||
|
import run.halo.app.model.enums.EncryptTypeEnum;
|
||||||
import run.halo.app.model.enums.PostEditorType;
|
import run.halo.app.model.enums.PostEditorType;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.vo.ArchiveYearVO;
|
import run.halo.app.model.vo.ArchiveYearVO;
|
||||||
import run.halo.app.model.vo.PostListVO;
|
import run.halo.app.model.vo.PostListVO;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
import run.halo.app.service.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
|
@ -59,6 +60,8 @@ public class PostModel {
|
||||||
|
|
||||||
private final AbstractStringCacheStore cacheStore;
|
private final AbstractStringCacheStore cacheStore;
|
||||||
|
|
||||||
|
private final AuthenticationService authenticationService;
|
||||||
|
|
||||||
public PostModel(PostService postService,
|
public PostModel(PostService postService,
|
||||||
ThemeService themeService,
|
ThemeService themeService,
|
||||||
PostCategoryService postCategoryService,
|
PostCategoryService postCategoryService,
|
||||||
|
@ -67,7 +70,8 @@ public class PostModel {
|
||||||
PostTagService postTagService,
|
PostTagService postTagService,
|
||||||
TagService tagService,
|
TagService tagService,
|
||||||
OptionService optionService,
|
OptionService optionService,
|
||||||
AbstractStringCacheStore cacheStore) {
|
AbstractStringCacheStore cacheStore,
|
||||||
|
AuthenticationService authenticationService) {
|
||||||
this.postService = postService;
|
this.postService = postService;
|
||||||
this.themeService = themeService;
|
this.themeService = themeService;
|
||||||
this.postCategoryService = postCategoryService;
|
this.postCategoryService = postCategoryService;
|
||||||
|
@ -77,32 +81,27 @@ public class PostModel {
|
||||||
this.tagService = tagService;
|
this.tagService = tagService;
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
this.cacheStore = cacheStore;
|
this.cacheStore = cacheStore;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String content(Post post, String token, Model model) {
|
public String content(Post post, String token, Model model) {
|
||||||
|
|
||||||
if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) {
|
if (post.getStatus().equals(PostStatus.INTIMATE)
|
||||||
|
&& !authenticationService.postAuthentication(post, null)) {
|
||||||
model.addAttribute("slug", post.getSlug());
|
model.addAttribute("slug", post.getSlug());
|
||||||
|
model.addAttribute("type", EncryptTypeEnum.POST.getName());
|
||||||
if (themeService.templateExists(POST_PASSWORD_TEMPLATE + SUFFIX_FTL)) {
|
if (themeService.templateExists(POST_PASSWORD_TEMPLATE + SUFFIX_FTL)) {
|
||||||
return themeService.render(POST_PASSWORD_TEMPLATE);
|
return themeService.render(POST_PASSWORD_TEMPLATE);
|
||||||
}
|
}
|
||||||
return "common/template/" + POST_PASSWORD_TEMPLATE;
|
return "common/template/" + POST_PASSWORD_TEMPLATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(token)) {
|
post = postService.getById(post.getId());
|
||||||
post = postService.getBy(PostStatus.PUBLISHED, post.getSlug());
|
|
||||||
|
if (post.getEditorType().equals(PostEditorType.MARKDOWN)) {
|
||||||
|
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
|
||||||
} else {
|
} else {
|
||||||
// verify token
|
post.setFormatContent(post.getOriginalContent());
|
||||||
String cachedToken = cacheStore.getAny(token, String.class)
|
|
||||||
.orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限"));
|
|
||||||
if (!cachedToken.equals(token)) {
|
|
||||||
throw new ForbiddenException("您没有该文章的访问权限");
|
|
||||||
}
|
|
||||||
if (post.getEditorType().equals(PostEditorType.MARKDOWN)) {
|
|
||||||
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
|
|
||||||
} else {
|
|
||||||
post.setFormatContent(post.getOriginalContent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
postService.publishVisitEvent(post.getId());
|
postService.publishVisitEvent(post.getId());
|
||||||
|
@ -112,7 +111,7 @@ public class PostModel {
|
||||||
postService.getNextPost(post).ifPresent(
|
postService.getNextPost(post).ifPresent(
|
||||||
nextPost -> model.addAttribute("nextPost", postService.convertToDetailVo(nextPost)));
|
nextPost -> model.addAttribute("nextPost", postService.convertToDetailVo(nextPost)));
|
||||||
|
|
||||||
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
|
List<Category> categories = postCategoryService.listCategoriesBy(post.getId(), false);
|
||||||
List<Tag> tags = postTagService.listTagsBy(post.getId());
|
List<Tag> tags = postTagService.listTagsBy(post.getId());
|
||||||
List<PostMeta> metas = postMetaService.listBy(post.getId());
|
List<PostMeta> metas = postMetaService.listBy(post.getId());
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class CategoryTagDirective implements TemplateDirectiveModel {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case "list":
|
case "list":
|
||||||
env.setVariable("categories", builder.build().wrap(postCategoryService
|
env.setVariable("categories", builder.build().wrap(postCategoryService
|
||||||
.listCategoryWithPostCountDto(Sort.by(DESC, "createTime"))));
|
.listCategoryWithPostCountDto(Sort.by(DESC, "createTime"), false)));
|
||||||
break;
|
break;
|
||||||
case "tree":
|
case "tree":
|
||||||
env.setVariable("categories", builder.build()
|
env.setVariable("categories", builder.build()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.core.freemarker.tag;
|
package run.halo.app.core.freemarker.tag;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import freemarker.core.Environment;
|
import freemarker.core.Environment;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.DefaultObjectWrapperBuilder;
|
import freemarker.template.DefaultObjectWrapperBuilder;
|
||||||
|
@ -77,12 +78,14 @@ public class PostTagDirective implements TemplateDirectiveModel {
|
||||||
case "listByCategoryId":
|
case "listByCategoryId":
|
||||||
Integer categoryId = Integer.parseInt(params.get("categoryId").toString());
|
Integer categoryId = Integer.parseInt(params.get("categoryId").toString());
|
||||||
env.setVariable("posts", builder.build().wrap(postService.convertToListVo(
|
env.setVariable("posts", builder.build().wrap(postService.convertToListVo(
|
||||||
postCategoryService.listPostBy(categoryId, PostStatus.PUBLISHED))));
|
postCategoryService.listPostBy(categoryId,
|
||||||
|
Sets.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE)))));
|
||||||
break;
|
break;
|
||||||
case "listByCategorySlug":
|
case "listByCategorySlug":
|
||||||
String categorySlug = params.get("categorySlug").toString();
|
String categorySlug = params.get("categorySlug").toString();
|
||||||
List<Post> posts =
|
List<Post> posts =
|
||||||
postCategoryService.listPostBy(categorySlug, PostStatus.PUBLISHED);
|
postCategoryService.listPostBy(categorySlug,
|
||||||
|
Sets.immutableEnumSet(PostStatus.PUBLISHED, PostStatus.INTIMATE));
|
||||||
env.setVariable("posts",
|
env.setVariable("posts",
|
||||||
builder.build().wrap(postService.convertToListVo(posts)));
|
builder.build().wrap(postService.convertToListVo(posts)));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package run.halo.app.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ZhiXiang Yuan
|
||||||
|
* @date 2021/01/18 20:13
|
||||||
|
*/
|
||||||
|
public class UnsupportedException extends ServiceException {
|
||||||
|
public UnsupportedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,8 @@ public class CategoryDTO implements OutputConverter<CategoryDTO, Category> {
|
||||||
|
|
||||||
private Integer parentId;
|
private Integer parentId;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
private String fullPath;
|
private String fullPath;
|
||||||
|
|
|
@ -73,6 +73,12 @@ public class Category extends BaseEntity {
|
||||||
@ColumnDefault("0")
|
@ColumnDefault("0")
|
||||||
private Integer parentId;
|
private Integer parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Category password.
|
||||||
|
*/
|
||||||
|
@Column(name = "password")
|
||||||
|
private String password;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
super.prePersist();
|
super.prePersist();
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package run.halo.app.model.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhixiang.yuan
|
||||||
|
* @since 2021/01/24 10:45:33
|
||||||
|
*/
|
||||||
|
public enum EncryptTypeEnum {
|
||||||
|
|
||||||
|
POST("post"), CATEGORY("category");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
EncryptTypeEnum(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ public class CategoryParam implements InputConverter<Category> {
|
||||||
@Size(max = 1023, message = "封面图链接的字符长度不能超过 {max}")
|
@Size(max = 1023, message = "封面图链接的字符长度不能超过 {max}")
|
||||||
private String thumbnail;
|
private String thumbnail;
|
||||||
|
|
||||||
|
@Size(max = 255, message = "分类密码的字符长度不能超过 {max}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
private Integer parentId = 0;
|
private Integer parentId = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -55,6 +55,19 @@ public interface PostCategoryRepository extends BaseRepository<PostCategory, Int
|
||||||
Set<Integer> findAllPostIdsByCategoryId(@NonNull Integer categoryId,
|
Set<Integer> findAllPostIdsByCategoryId(@NonNull Integer categoryId,
|
||||||
@NonNull PostStatus status);
|
@NonNull PostStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all post ids by category id and post status.
|
||||||
|
*
|
||||||
|
* @param categoryId category id must not be null
|
||||||
|
* @param status post status must not be empty
|
||||||
|
* @return a set of post id
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
@Query("select postCategory.postId from PostCategory postCategory, Post post where"
|
||||||
|
+ " postCategory.categoryId = ?1 and post.id = postCategory.postId and post.status in (?2)")
|
||||||
|
Set<Integer> findAllPostIdsByCategoryId(
|
||||||
|
@NonNull Integer categoryId, @NonNull Set<PostStatus> status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all post categories by post id in.
|
* Finds all post categories by post id in.
|
||||||
*
|
*
|
||||||
|
@ -104,4 +117,14 @@ public interface PostCategoryRepository extends BaseRepository<PostCategory, Int
|
||||||
+ ", pc.categoryId) from PostCategory pc group by pc.categoryId")
|
+ ", pc.categoryId) from PostCategory pc group by pc.categoryId")
|
||||||
@NonNull
|
@NonNull
|
||||||
List<CategoryPostCountProjection> findPostCount();
|
List<CategoryPostCountProjection> findPostCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all post categories by category id list.
|
||||||
|
*
|
||||||
|
* @param categoryIdList category id list must not be empty
|
||||||
|
* @return a list of post category
|
||||||
|
*/
|
||||||
|
@Query("select pc from PostCategory pc where pc.categoryId in (?1)")
|
||||||
|
@NonNull
|
||||||
|
List<PostCategory> findAllByCategoryIdList(List<Integer> categoryIdList);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package run.halo.app.service;
|
||||||
|
|
||||||
|
import run.halo.app.model.entity.Post;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication service
|
||||||
|
*
|
||||||
|
* @author ZhiXiang Yuan
|
||||||
|
* @date 2021/01/20 17:39
|
||||||
|
*/
|
||||||
|
public interface AuthenticationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* post authentication
|
||||||
|
*
|
||||||
|
* @param post post
|
||||||
|
* @param password password
|
||||||
|
* @return authentication success or fail
|
||||||
|
*/
|
||||||
|
boolean postAuthentication(Post post, String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* category authentication
|
||||||
|
*
|
||||||
|
* @param categoryId category id
|
||||||
|
* @param password password
|
||||||
|
* @return authentication success or fail
|
||||||
|
*/
|
||||||
|
boolean categoryAuthentication(Integer categoryId, String password);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package run.halo.app.service;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ZhiXiang Yuan
|
||||||
|
* @date 2021/01/20 17:40
|
||||||
|
*/
|
||||||
|
public interface AuthorizationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build post token
|
||||||
|
*
|
||||||
|
* @param postId post id
|
||||||
|
* @return token
|
||||||
|
*/
|
||||||
|
static String buildPostToken(Integer postId) {
|
||||||
|
return "POST:" + postId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build category token
|
||||||
|
*
|
||||||
|
* @param categoryId category id
|
||||||
|
* @return token
|
||||||
|
*/
|
||||||
|
static String buildCategoryToken(Integer categoryId) {
|
||||||
|
return "CATEGORY:" + categoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post authorization
|
||||||
|
*
|
||||||
|
* @param postId post id
|
||||||
|
*/
|
||||||
|
void postAuthorization(Integer postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CategoryAuthorization
|
||||||
|
*
|
||||||
|
* @param categoryId category id
|
||||||
|
*/
|
||||||
|
void categoryAuthorization(Integer categoryId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access permission store
|
||||||
|
*
|
||||||
|
* @return access permission store
|
||||||
|
*/
|
||||||
|
Set<String> getAccessPermissionStore();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete article authorization
|
||||||
|
*
|
||||||
|
* @param postId post id
|
||||||
|
*/
|
||||||
|
void deletePostAuthorization(Integer postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete category Authorization
|
||||||
|
*
|
||||||
|
* @param categoryId category id
|
||||||
|
*/
|
||||||
|
void deleteCategoryAuthorization(Integer categoryId);
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.service;
|
package run.halo.app.service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
@ -35,7 +36,6 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
* @param slug slug
|
* @param slug slug
|
||||||
* @return Category
|
* @return Category
|
||||||
*/
|
*/
|
||||||
@NonNull
|
|
||||||
Category getBySlug(@NonNull String slug);
|
Category getBySlug(@NonNull String slug);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,6 +47,16 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
@NonNull
|
@NonNull
|
||||||
Category getBySlugOfNonNull(String slug);
|
Category getBySlugOfNonNull(String slug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get category by slug
|
||||||
|
*
|
||||||
|
* @param slug slug
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
|
* @return Category
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Category getBySlugOfNonNull(String slug, boolean queryEncryptCategory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Category by name.
|
* Get Category by name.
|
||||||
*
|
*
|
||||||
|
@ -64,6 +74,14 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
@Transactional
|
@Transactional
|
||||||
void removeCategoryAndPostCategoryBy(Integer categoryId);
|
void removeCategoryAndPostCategoryBy(Integer categoryId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh post status, when the post is under the encryption category or is has a password,
|
||||||
|
* it is changed to private, otherwise it is changed to public.
|
||||||
|
*
|
||||||
|
* @param affectedPostIdList affected post id list
|
||||||
|
*/
|
||||||
|
void refreshPostStatus(List<Integer> affectedPostIdList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List categories by parent id.
|
* List categories by parent id.
|
||||||
*
|
*
|
||||||
|
@ -72,6 +90,26 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
*/
|
*/
|
||||||
List<Category> listByParentId(@NonNull Integer id);
|
List<Category> listByParentId(@NonNull Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all category not encrypt.
|
||||||
|
*
|
||||||
|
* @param sort sort
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
|
* @return list of category.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Category> listAll(Sort sort, boolean queryEncryptCategory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all by ids
|
||||||
|
*
|
||||||
|
* @param ids ids
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
|
* @return List
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Category> listAllByIds(Collection<Integer> ids, boolean queryEncryptCategory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts to category dto.
|
* Converts to category dto.
|
||||||
*
|
*
|
||||||
|
@ -89,4 +127,22 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
List<CategoryDTO> convertTo(@Nullable List<Category> categories);
|
List<CategoryDTO> convertTo(@Nullable List<Category> categories);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter encrypt category
|
||||||
|
*
|
||||||
|
* @param categories this categories is not a category list tree
|
||||||
|
* @return category list
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Category> filterEncryptCategory(@Nullable List<Category> categories);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the category is encrypted.
|
||||||
|
*
|
||||||
|
* @param categoryId category id
|
||||||
|
* @return whether to encrypt
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Boolean categoryHasEncrypt(Integer categoryId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,26 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
||||||
@NonNull
|
@NonNull
|
||||||
List<Category> listCategoriesBy(@NonNull Integer postId);
|
List<Category> listCategoriesBy(@NonNull Integer postId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists category by post id.
|
||||||
|
*
|
||||||
|
* @param postId post id must not be null
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
|
* @return a list of category
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Category> listCategoriesBy(@NonNull Integer postId, @NonNull boolean queryEncryptCategory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List category list map by post id collection.
|
* List category list map by post id collection.
|
||||||
*
|
*
|
||||||
* @param postIds post id collection
|
* @param postIds post id collection
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
* @return a category list map (key: postId, value: a list of category)
|
* @return a category list map (key: postId, value: a list of category)
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
Map<Integer, List<Category>> listCategoryListMap(@Nullable Collection<Integer> postIds);
|
Map<Integer, List<Category>> listCategoryListMap(
|
||||||
|
@Nullable Collection<Integer> postIds, @NonNull boolean queryEncryptCategory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists post by category id.
|
* Lists post by category id.
|
||||||
|
@ -63,6 +75,16 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
||||||
@NonNull
|
@NonNull
|
||||||
List<Post> listPostBy(@NonNull Integer categoryId, @NonNull PostStatus status);
|
List<Post> listPostBy(@NonNull Integer categoryId, @NonNull PostStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists post by category id and post status.
|
||||||
|
*
|
||||||
|
* @param categoryId category id must not be null
|
||||||
|
* @param status post status
|
||||||
|
* @return a list of post
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Post> listPostBy(@NonNull Integer categoryId, @NonNull Set<PostStatus> status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists post by category slug and post status.
|
* Lists post by category slug and post status.
|
||||||
*
|
*
|
||||||
|
@ -73,6 +95,16 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
||||||
@NonNull
|
@NonNull
|
||||||
List<Post> listPostBy(@NonNull String slug, @NonNull PostStatus status);
|
List<Post> listPostBy(@NonNull String slug, @NonNull PostStatus status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists post by category slug and post status.
|
||||||
|
*
|
||||||
|
* @param slug category slug must not be null
|
||||||
|
* @param status post status
|
||||||
|
* @return a list of post
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<Post> listPostBy(@NonNull String slug, @NonNull Set<PostStatus> status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pages post by category id.
|
* Pages post by category id.
|
||||||
*
|
*
|
||||||
|
@ -95,6 +127,18 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
||||||
Page<Post> pagePostBy(@NonNull Integer categoryId, @NonNull PostStatus status,
|
Page<Post> pagePostBy(@NonNull Integer categoryId, @NonNull PostStatus status,
|
||||||
Pageable pageable);
|
Pageable pageable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pages post by category id and post status.
|
||||||
|
*
|
||||||
|
* @param categoryId category id must not be null
|
||||||
|
* @param status post status
|
||||||
|
* @param pageable pageable
|
||||||
|
* @return page of post
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Page<Post> pagePostBy(
|
||||||
|
@NonNull Integer categoryId, @NonNull Set<PostStatus> status, Pageable pageable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges or creates post categories by post id and category id set if absent.
|
* Merges or creates post categories by post id and category id set if absent.
|
||||||
*
|
*
|
||||||
|
@ -157,8 +201,19 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
||||||
* Lists category with post count.
|
* Lists category with post count.
|
||||||
*
|
*
|
||||||
* @param sort sort info
|
* @param sort sort info
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
* @return a list of category dto
|
* @return a list of category dto
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
List<CategoryWithPostCountDTO> listCategoryWithPostCountDto(@NonNull Sort sort);
|
List<CategoryWithPostCountDTO> listCategoryWithPostCountDto(
|
||||||
|
@NonNull Sort sort, @NonNull boolean queryEncryptCategory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists by category id.
|
||||||
|
*
|
||||||
|
* @param categoryIdList category id must not be empty
|
||||||
|
* @return a list of post category
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<PostCategory> listByCategoryIdList(@NonNull List<Integer> categoryIdList);
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,6 +248,16 @@ public interface PostService extends BasePostService<Post> {
|
||||||
*/
|
*/
|
||||||
Page<PostDetailVO> convertToDetailVo(@NonNull Page<Post> postPage);
|
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.
|
* Converts to a page of post list vo.
|
||||||
*
|
*
|
||||||
|
@ -257,6 +267,16 @@ public interface PostService extends BasePostService<Post> {
|
||||||
@NonNull
|
@NonNull
|
||||||
Page<PostListVO> convertToListVo(@NonNull Page<Post> postPage);
|
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.
|
* Converts to a list of post list vo.
|
||||||
*
|
*
|
||||||
|
@ -266,6 +286,14 @@ public interface PostService extends BasePostService<Post> {
|
||||||
@NonNull
|
@NonNull
|
||||||
List<PostListVO> convertToListVo(@NonNull List<Post> posts);
|
List<PostListVO> convertToListVo(@NonNull List<Post> posts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts to a list of post list vo.
|
||||||
|
*
|
||||||
|
* @param posts post must not be null
|
||||||
|
* @param queryEncryptCategory whether to query encryption category
|
||||||
|
* @return a list of post list vo
|
||||||
|
*/
|
||||||
|
List<PostListVO> convertToListVo(List<Post> posts, boolean queryEncryptCategory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publish a post visit event.
|
* Publish a post visit event.
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
package run.halo.app.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import run.halo.app.model.entity.Category;
|
||||||
|
import run.halo.app.model.entity.Post;
|
||||||
|
import run.halo.app.repository.CategoryRepository;
|
||||||
|
import run.halo.app.repository.PostCategoryRepository;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
|
import run.halo.app.service.AuthorizationService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ZhiXiang Yuan
|
||||||
|
* @date 2021/01/20 17:56
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AuthenticationServiceImpl implements AuthenticationService {
|
||||||
|
|
||||||
|
private final CategoryRepository categoryRepository;
|
||||||
|
|
||||||
|
private final AuthorizationService authorizationService;
|
||||||
|
|
||||||
|
private final PostCategoryRepository postCategoryRepository;
|
||||||
|
|
||||||
|
public AuthenticationServiceImpl(PostCategoryRepository postCategoryRepository,
|
||||||
|
CategoryRepository categoryRepository,
|
||||||
|
AuthorizationService authorizationService
|
||||||
|
) {
|
||||||
|
this.postCategoryRepository = postCategoryRepository;
|
||||||
|
this.categoryRepository = categoryRepository;
|
||||||
|
this.authorizationService = authorizationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean postAuthentication(Post post, String password) {
|
||||||
|
Set<String> accessPermissionStore = authorizationService.getAccessPermissionStore();
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(post.getPassword())) {
|
||||||
|
if (accessPermissionStore.contains(AuthorizationService.buildPostToken(post.getId()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (post.getPassword().equals(password)) {
|
||||||
|
authorizationService.postAuthorization(post.getId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Integer> allCategoryIdSet = postCategoryRepository
|
||||||
|
.findAllCategoryIdsByPostId(post.getId());
|
||||||
|
|
||||||
|
if (allCategoryIdSet.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer categoryId : allCategoryIdSet) {
|
||||||
|
if (categoryAuthentication(categoryId, password)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean categoryAuthentication(Integer categoryId, String password) {
|
||||||
|
|
||||||
|
Map<Integer, Category> idToCategoryMap = categoryRepository.findAll().stream()
|
||||||
|
.collect(Collectors.toMap(Category::getId, Function.identity()));
|
||||||
|
|
||||||
|
Set<String> accessPermissionStore = authorizationService.getAccessPermissionStore();
|
||||||
|
|
||||||
|
return doCategoryAuthentication(
|
||||||
|
idToCategoryMap, accessPermissionStore, categoryId, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doCategoryAuthentication(Map<Integer, Category> idToCategoryMap,
|
||||||
|
Set<String> accessPermissionStore,
|
||||||
|
Integer categoryId, String password) {
|
||||||
|
|
||||||
|
Category category = idToCategoryMap.get(categoryId);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(category.getPassword())) {
|
||||||
|
if (accessPermissionStore.contains(
|
||||||
|
AuthorizationService.buildCategoryToken(category.getId()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category.getPassword().equals(password)) {
|
||||||
|
authorizationService.categoryAuthorization(category.getId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category.getParentId() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doCategoryAuthentication(
|
||||||
|
idToCategoryMap, accessPermissionStore, category.getParentId(), password);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package run.halo.app.service.impl;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import run.halo.app.cache.AbstractStringCacheStore;
|
||||||
|
import run.halo.app.service.AuthorizationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ZhiXiang Yuan
|
||||||
|
* @date 2021/01/21 11:28
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AuthorizationServiceImpl implements AuthorizationService {
|
||||||
|
|
||||||
|
private final AbstractStringCacheStore cacheStore;
|
||||||
|
|
||||||
|
public AuthorizationServiceImpl(AbstractStringCacheStore cacheStore) {
|
||||||
|
this.cacheStore = cacheStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postAuthorization(Integer postId) {
|
||||||
|
doAuthorization(AuthorizationService.buildPostToken(postId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void categoryAuthorization(Integer categoryId) {
|
||||||
|
doAuthorization(AuthorizationService.buildCategoryToken(categoryId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getAccessPermissionStore() {
|
||||||
|
return cacheStore.getAny(buildAccessPermissionKey(), Set.class).orElse(new HashSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deletePostAuthorization(Integer postId) {
|
||||||
|
doDeleteAuthorization(AuthorizationService.buildPostToken(postId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteCategoryAuthorization(Integer categoryId) {
|
||||||
|
doDeleteAuthorization(AuthorizationService.buildCategoryToken(categoryId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDeleteAuthorization(String value) {
|
||||||
|
Set<String> accessStore = getAccessPermissionStore();
|
||||||
|
|
||||||
|
accessStore.remove(value);
|
||||||
|
|
||||||
|
cacheStore.putAny(buildAccessPermissionKey(), accessStore, 1, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doAuthorization(String value) {
|
||||||
|
Set<String> accessStore = getAccessPermissionStore();
|
||||||
|
|
||||||
|
accessStore.add(value);
|
||||||
|
|
||||||
|
cacheStore.putAny(buildAccessPermissionKey(), accessStore, 1, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildAccessPermissionKey() {
|
||||||
|
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
|
||||||
|
.getRequestAttributes();
|
||||||
|
|
||||||
|
HttpServletRequest request = requestAttributes.getRequest();
|
||||||
|
|
||||||
|
return "ACCESS_PERMISSION: " + request.getSession().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -291,11 +291,6 @@ public abstract class BasePostServiceImpl<POST extends BasePost>
|
||||||
post.setFormatContent(post.getOriginalContent());
|
post.setFormatContent(post.getOriginalContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if password is not empty,change status to intimate
|
|
||||||
if (StringUtils.isNotEmpty(post.getPassword()) && post.getStatus() != PostStatus.DRAFT) {
|
|
||||||
post.setStatus(PostStatus.INTIMATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or update post
|
// Create or update post
|
||||||
if (ServiceUtils.isEmptyId(post.getId())) {
|
if (ServiceUtils.isEmptyId(post.getId())) {
|
||||||
// The sheet will be created
|
// The sheet will be created
|
||||||
|
|
|
@ -2,12 +2,23 @@ package run.halo.app.service.impl;
|
||||||
|
|
||||||
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -16,14 +27,22 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import run.halo.app.exception.AlreadyExistsException;
|
import run.halo.app.exception.AlreadyExistsException;
|
||||||
import run.halo.app.exception.NotFoundException;
|
import run.halo.app.exception.NotFoundException;
|
||||||
|
import run.halo.app.exception.UnsupportedException;
|
||||||
import run.halo.app.model.dto.CategoryDTO;
|
import run.halo.app.model.dto.CategoryDTO;
|
||||||
import run.halo.app.model.entity.Category;
|
import run.halo.app.model.entity.Category;
|
||||||
|
import run.halo.app.model.entity.Post;
|
||||||
|
import run.halo.app.model.entity.PostCategory;
|
||||||
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.vo.CategoryVO;
|
import run.halo.app.model.vo.CategoryVO;
|
||||||
import run.halo.app.repository.CategoryRepository;
|
import run.halo.app.repository.CategoryRepository;
|
||||||
|
import run.halo.app.service.AuthenticationService;
|
||||||
|
import run.halo.app.service.AuthorizationService;
|
||||||
import run.halo.app.service.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
|
import run.halo.app.service.PostService;
|
||||||
import run.halo.app.service.base.AbstractCrudService;
|
import run.halo.app.service.base.AbstractCrudService;
|
||||||
|
import run.halo.app.utils.BeanUtils;
|
||||||
import run.halo.app.utils.ServiceUtils;
|
import run.halo.app.utils.ServiceUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,13 +63,29 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
private final AuthorizationService authorizationService;
|
||||||
|
|
||||||
|
private PostService postService;
|
||||||
|
|
||||||
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
public CategoryServiceImpl(CategoryRepository categoryRepository,
|
public CategoryServiceImpl(CategoryRepository categoryRepository,
|
||||||
PostCategoryService postCategoryService,
|
PostCategoryService postCategoryService,
|
||||||
OptionService optionService) {
|
OptionService optionService,
|
||||||
|
AuthenticationService authenticationService,
|
||||||
|
AuthorizationService authorizationService) {
|
||||||
super(categoryRepository);
|
super(categoryRepository);
|
||||||
this.categoryRepository = categoryRepository;
|
this.categoryRepository = categoryRepository;
|
||||||
this.postCategoryService = postCategoryService;
|
this.postCategoryService = postCategoryService;
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.authenticationService = authenticationService;
|
||||||
|
this.authorizationService = authorizationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Autowired
|
||||||
|
public void setPostService(PostService postService) {
|
||||||
|
this.postService = postService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,6 +113,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(category.getPassword())) {
|
||||||
|
category.setPassword(category.getPassword().trim());
|
||||||
|
}
|
||||||
|
|
||||||
// Create it
|
// Create it
|
||||||
return super.create(category);
|
return super.create(category);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +136,7 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
CategoryVO topLevelCategory = createTopLevelCategory();
|
CategoryVO topLevelCategory = createTopLevelCategory();
|
||||||
|
|
||||||
// Concrete the tree
|
// Concrete the tree
|
||||||
concreteTree(topLevelCategory, categories);
|
concreteTree(topLevelCategory, categories, false);
|
||||||
|
|
||||||
return topLevelCategory.getChildren();
|
return topLevelCategory.getChildren();
|
||||||
}
|
}
|
||||||
|
@ -107,8 +146,13 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
*
|
*
|
||||||
* @param parentCategory parent category vo must not be null
|
* @param parentCategory parent category vo must not be null
|
||||||
* @param categories a list of category
|
* @param categories a list of category
|
||||||
|
* @param fillPassword whether to fill in the password
|
||||||
*/
|
*/
|
||||||
private void concreteTree(CategoryVO parentCategory, List<Category> categories) {
|
private void concreteTree(
|
||||||
|
CategoryVO parentCategory,
|
||||||
|
List<Category> categories,
|
||||||
|
Boolean fillPassword
|
||||||
|
) {
|
||||||
Assert.notNull(parentCategory, "Parent category must not be null");
|
Assert.notNull(parentCategory, "Parent category must not be null");
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(categories)) {
|
if (CollectionUtils.isEmpty(categories)) {
|
||||||
|
@ -142,6 +186,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
|
|
||||||
child.setFullPath(fullPath.toString());
|
child.setFullPath(fullPath.toString());
|
||||||
|
|
||||||
|
if (!fillPassword) {
|
||||||
|
child.setPassword(null);
|
||||||
|
}
|
||||||
|
|
||||||
// Add child
|
// Add child
|
||||||
parentCategory.getChildren().add(child);
|
parentCategory.getChildren().add(child);
|
||||||
});
|
});
|
||||||
|
@ -152,7 +200,7 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
// Foreach children vos
|
// Foreach children vos
|
||||||
if (!CollectionUtils.isEmpty(parentCategory.getChildren())) {
|
if (!CollectionUtils.isEmpty(parentCategory.getChildren())) {
|
||||||
parentCategory.getChildren()
|
parentCategory.getChildren()
|
||||||
.forEach(childCategory -> concreteTree(childCategory, categories));
|
.forEach(childCategory -> concreteTree(childCategory, categories, fillPassword));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,18 +222,58 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Category getBySlug(String slug) {
|
public Category getBySlug(String slug) {
|
||||||
return categoryRepository.getBySlug(slug).orElse(null);
|
Optional<Category> bySlug = categoryRepository.getBySlug(slug);
|
||||||
|
if (bySlug.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Category category = bySlug.get();
|
||||||
|
|
||||||
|
if (authenticationService.categoryAuthentication(category.getId(), null)) {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Category getBySlugOfNonNull(String slug) {
|
public Category getBySlugOfNonNull(String slug) {
|
||||||
return categoryRepository.getBySlug(slug)
|
|
||||||
.orElseThrow(() -> new NotFoundException("查询不到该分类的信息").setErrorData(slug));
|
Category category = categoryRepository
|
||||||
|
.getBySlug(slug)
|
||||||
|
.orElseThrow(() -> new NotFoundException("查询不到该分类的信息").setErrorData(slug));
|
||||||
|
|
||||||
|
if (authenticationService.categoryAuthentication(category.getId(), null)) {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotFoundException("查询不到该分类的信息").setErrorData(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Category getBySlugOfNonNull(String slug, boolean queryEncryptCategory) {
|
||||||
|
if (queryEncryptCategory) {
|
||||||
|
return categoryRepository.getBySlug(slug)
|
||||||
|
.orElseThrow(() -> new NotFoundException("查询不到该分类的信息").setErrorData(slug));
|
||||||
|
} else {
|
||||||
|
return this.getBySlugOfNonNull(slug);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Category getByName(String name) {
|
public Category getByName(String name) {
|
||||||
return categoryRepository.getByName(name).orElse(null);
|
Optional<Category> byName = categoryRepository.getByName(name);
|
||||||
|
if (byName.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Category category = byName.get();
|
||||||
|
|
||||||
|
if (authenticationService.categoryAuthentication(category.getId(), null)) {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -198,10 +286,44 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
update(category);
|
update(category);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove category
|
// Remove category
|
||||||
removeById(categoryId);
|
removeById(categoryId);
|
||||||
// Remove post categories
|
// Remove post categories
|
||||||
postCategoryService.removeByCategoryId(categoryId);
|
List<Integer> affectedPostIdList = postCategoryService.removeByCategoryId(categoryId)
|
||||||
|
.stream().map(PostCategory::getPostId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
refreshPostStatus(affectedPostIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshPostStatus(List<Integer> affectedPostIdList) {
|
||||||
|
if (CollectionUtil.isEmpty(affectedPostIdList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer postId : affectedPostIdList) {
|
||||||
|
Post post = postService.getById(postId);
|
||||||
|
|
||||||
|
post.setStatus(null);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(post.getPassword())) {
|
||||||
|
post.setStatus(PostStatus.INTIMATE);
|
||||||
|
} else {
|
||||||
|
postCategoryService.listByPostId(postId)
|
||||||
|
.stream().map(PostCategory::getCategoryId)
|
||||||
|
.filter(this::categoryHasEncrypt)
|
||||||
|
.findAny()
|
||||||
|
.ifPresent(id -> post.setStatus(PostStatus.INTIMATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (post.getStatus() == null) {
|
||||||
|
post.setStatus(PostStatus.PUBLISHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
postService.update(post);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -243,4 +365,302 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
.map(this::convertTo)
|
.map(this::convertTo)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> filterEncryptCategory(List<Category> categories) {
|
||||||
|
if (CollectionUtil.isEmpty(categories)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concrete the tree
|
||||||
|
CategoryVO topLevelCategory = createTopLevelCategory();
|
||||||
|
|
||||||
|
concreteTree(topLevelCategory, categories, true);
|
||||||
|
|
||||||
|
List<CategoryVO> childrenList = topLevelCategory.getChildren();
|
||||||
|
|
||||||
|
// filter encrypt category
|
||||||
|
doFilterEncryptCategory(childrenList);
|
||||||
|
|
||||||
|
List<Category> collectorList = new ArrayList<>();
|
||||||
|
|
||||||
|
collectAllChild(collectorList, childrenList, true);
|
||||||
|
|
||||||
|
for (Category category : collectorList) {
|
||||||
|
category.setPassword(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return collectorList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do filter encrypt category
|
||||||
|
*
|
||||||
|
* @param categoryList category list
|
||||||
|
*/
|
||||||
|
private void doFilterEncryptCategory(List<CategoryVO> categoryList) {
|
||||||
|
if (CollectionUtil.isEmpty(categoryList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CategoryVO categoryVO : categoryList) {
|
||||||
|
if (!authenticationService.categoryAuthentication(categoryVO.getId(), null)) {
|
||||||
|
// if parent category is not certified, the child category is not displayed.
|
||||||
|
categoryVO.setChildren(null);
|
||||||
|
} else {
|
||||||
|
doFilterEncryptCategory(categoryVO.getChildren());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect all child from tree
|
||||||
|
*
|
||||||
|
* @param collectorList collector
|
||||||
|
* @param childrenList contains categories of children
|
||||||
|
* @param doNotCollectEncryptedCategory true is not collect, false is collect
|
||||||
|
*/
|
||||||
|
private void collectAllChild(List<Category> collectorList,
|
||||||
|
List<CategoryVO> childrenList,
|
||||||
|
Boolean doNotCollectEncryptedCategory) {
|
||||||
|
if (CollectionUtil.isEmpty(childrenList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CategoryVO categoryVO : childrenList) {
|
||||||
|
|
||||||
|
Category category = new Category();
|
||||||
|
BeanUtils.updateProperties(categoryVO, category);
|
||||||
|
|
||||||
|
collectorList.add(category);
|
||||||
|
|
||||||
|
if (doNotCollectEncryptedCategory
|
||||||
|
&& !authenticationService.categoryAuthentication(category.getId(), null)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtil.isNotEmpty(categoryVO.getChildren())) {
|
||||||
|
collectAllChild(collectorList,
|
||||||
|
categoryVO.getChildren(), doNotCollectEncryptedCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect sub-categories under the specified category.
|
||||||
|
*
|
||||||
|
* @param collectorList collector
|
||||||
|
* @param childrenList contains categories of children
|
||||||
|
* @param categoryId category id
|
||||||
|
* @param doNotCollectEncryptedCategory true is not collect, false is collect
|
||||||
|
*/
|
||||||
|
private void collectAllChildByCategoryId(List<Category> collectorList,
|
||||||
|
List<CategoryVO> childrenList,
|
||||||
|
Integer categoryId,
|
||||||
|
Boolean doNotCollectEncryptedCategory) {
|
||||||
|
if (CollectionUtil.isEmpty(childrenList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CategoryVO categoryVO : childrenList) {
|
||||||
|
if (categoryVO.getId().equals(categoryId)) {
|
||||||
|
collectAllChild(collectorList,
|
||||||
|
categoryVO.getChildren(), doNotCollectEncryptedCategory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAll(Sort sort, boolean queryEncryptCategory) {
|
||||||
|
if (queryEncryptCategory) {
|
||||||
|
return super.listAll(sort);
|
||||||
|
} else {
|
||||||
|
return this.listAll(sort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAll() {
|
||||||
|
return filterEncryptCategory(super.listAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAll(Sort sort) {
|
||||||
|
return filterEncryptCategory(super.listAll(sort));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Category> listAll(Pageable pageable) {
|
||||||
|
// To prevent developers from querying encrypted categories,
|
||||||
|
// so paging query operations are not supported here. If you
|
||||||
|
// really need to use this method, refactor this method to do memory paging.
|
||||||
|
throw new UnsupportedException("Does not support business layer paging query.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAllByIds(Collection<Integer> integers, boolean queryEncryptCategory) {
|
||||||
|
if (queryEncryptCategory) {
|
||||||
|
return super.listAllByIds(integers);
|
||||||
|
} else {
|
||||||
|
return this.listAllByIds(integers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAllByIds(Collection<Integer> integers) {
|
||||||
|
return filterEncryptCategory(super.listAllByIds(integers));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listAllByIds(Collection<Integer> integers, Sort sort) {
|
||||||
|
return filterEncryptCategory(super.listAllByIds(integers, sort));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Category update(Category category) {
|
||||||
|
Category update = super.update(category);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(category.getPassword())) {
|
||||||
|
doEncryptPost(category);
|
||||||
|
} else {
|
||||||
|
doDecryptPost(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove authorization every time an category is updated.
|
||||||
|
authorizationService.deleteCategoryAuthorization(category.getId());
|
||||||
|
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypting a category requires encrypting all articles under the category
|
||||||
|
*
|
||||||
|
* @param category need encrypt category
|
||||||
|
*/
|
||||||
|
private void doEncryptPost(Category category) {
|
||||||
|
CategoryVO topLevelCategory = createTopLevelCategory();
|
||||||
|
|
||||||
|
concreteTree(topLevelCategory, super.listAll(), true);
|
||||||
|
|
||||||
|
List<Category> collectorList = new ArrayList<>();
|
||||||
|
|
||||||
|
collectAllChildByCategoryId(collectorList,
|
||||||
|
topLevelCategory.getChildren(), category.getId(), true);
|
||||||
|
|
||||||
|
Optional.of(collectorList.stream().map(Category::getId).collect(Collectors.toList()))
|
||||||
|
.map(categoryIdList -> {
|
||||||
|
categoryIdList.add(category.getId());
|
||||||
|
return categoryIdList;
|
||||||
|
})
|
||||||
|
.map(postCategoryService::listByCategoryIdList)
|
||||||
|
|
||||||
|
.filter(postCategoryList -> !postCategoryList.isEmpty())
|
||||||
|
.map(postCategoryList -> postCategoryList
|
||||||
|
.stream().map(PostCategory::getPostId).distinct().collect(Collectors.toList()))
|
||||||
|
|
||||||
|
.filter(postIdList -> !postIdList.isEmpty())
|
||||||
|
.map(postIdList -> postService.listAllByIds(postIdList))
|
||||||
|
|
||||||
|
.filter(postList -> !postList.isEmpty())
|
||||||
|
.map(postList -> postList.stream()
|
||||||
|
.filter(post -> PostStatus.PUBLISHED.equals(post.getStatus()))
|
||||||
|
.map(Post::getId).collect(Collectors.toList()))
|
||||||
|
|
||||||
|
.filter(postIdList -> !postIdList.isEmpty())
|
||||||
|
.map(postIdList -> postService.updateStatusByIds(postIdList, PostStatus.INTIMATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDecryptPost(Category category) {
|
||||||
|
|
||||||
|
List<Category> allCategoryList = super.listAll();
|
||||||
|
|
||||||
|
Map<Integer, Category> idToCategoryMap = allCategoryList.stream().collect(
|
||||||
|
Collectors.toMap(Category::getId, Function.identity()));
|
||||||
|
|
||||||
|
if (doCategoryHasEncrypt(idToCategoryMap, category.getParentId())) {
|
||||||
|
// If the parent category is encrypted, there is no need to update the encryption status
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CategoryVO topLevelCategory = createTopLevelCategory();
|
||||||
|
|
||||||
|
concreteTree(topLevelCategory, allCategoryList, true);
|
||||||
|
|
||||||
|
List<Category> collectorList = new ArrayList<>();
|
||||||
|
|
||||||
|
// Only collect unencrypted sub-categories under the category.
|
||||||
|
collectAllChildByCategoryId(collectorList,
|
||||||
|
topLevelCategory.getChildren(), category.getId(), false);
|
||||||
|
// Collect the currently decrypted category
|
||||||
|
collectorList.add(category);
|
||||||
|
|
||||||
|
Optional.of(collectorList.stream().map(Category::getId).collect(Collectors.toList()))
|
||||||
|
.map(postCategoryService::listByCategoryIdList)
|
||||||
|
|
||||||
|
.filter(postCategoryList -> !postCategoryList.isEmpty())
|
||||||
|
.map(postCategoryList -> postCategoryList
|
||||||
|
.stream().map(PostCategory::getPostId).distinct().collect(Collectors.toList()))
|
||||||
|
|
||||||
|
.filter(postIdList -> !postIdList.isEmpty())
|
||||||
|
.map(postIdList -> postService.listAllByIds(postIdList))
|
||||||
|
|
||||||
|
.filter(postList -> !postList.isEmpty())
|
||||||
|
.map(postList -> postList.stream()
|
||||||
|
.filter(post -> StrUtil.isBlank(post.getPassword()))
|
||||||
|
.filter(post -> PostStatus.INTIMATE.equals(post.getStatus()))
|
||||||
|
.map(Post::getId).collect(Collectors.toList()))
|
||||||
|
|
||||||
|
.filter(postIdList -> !postIdList.isEmpty())
|
||||||
|
.map(postIdList -> postService.updateStatusByIds(postIdList, PostStatus.PUBLISHED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean categoryHasEncrypt(Integer categoryId) {
|
||||||
|
List<Category> allCategoryList = super.listAll();
|
||||||
|
|
||||||
|
Map<Integer, Category> idToCategoryMap = allCategoryList.stream().collect(
|
||||||
|
Collectors.toMap(Category::getId, Function.identity()));
|
||||||
|
|
||||||
|
return doCategoryHasEncrypt(idToCategoryMap, categoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find whether the parent category is encrypted.
|
||||||
|
*
|
||||||
|
* @param idToCategoryMap find category by id
|
||||||
|
* @param categoryId category id
|
||||||
|
* @return whether to encrypt
|
||||||
|
*/
|
||||||
|
private boolean doCategoryHasEncrypt(
|
||||||
|
Map<Integer, Category> idToCategoryMap, Integer categoryId) {
|
||||||
|
|
||||||
|
if (categoryId == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Category category = idToCategoryMap.get(categoryId);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(category.getPassword())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doCategoryHasEncrypt(idToCategoryMap, category.getParentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> updateInBatch(Collection<Category> categories) {
|
||||||
|
if (CollectionUtils.isEmpty(categories)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Category> resultList = new ArrayList<>();
|
||||||
|
for (Category category : categories) {
|
||||||
|
resultList.add(update(category));
|
||||||
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,11 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
@ -23,9 +26,9 @@ import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.entity.PostCategory;
|
import run.halo.app.model.entity.PostCategory;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.projection.CategoryPostCountProjection;
|
import run.halo.app.model.projection.CategoryPostCountProjection;
|
||||||
import run.halo.app.repository.CategoryRepository;
|
|
||||||
import run.halo.app.repository.PostCategoryRepository;
|
import run.halo.app.repository.PostCategoryRepository;
|
||||||
import run.halo.app.repository.PostRepository;
|
import run.halo.app.repository.PostRepository;
|
||||||
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
import run.halo.app.service.base.AbstractCrudService;
|
import run.halo.app.service.base.AbstractCrudService;
|
||||||
|
@ -47,33 +50,44 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
|
|
||||||
private final PostRepository postRepository;
|
private final PostRepository postRepository;
|
||||||
|
|
||||||
private final CategoryRepository categoryRepository;
|
private CategoryService categoryService;
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
public PostCategoryServiceImpl(PostCategoryRepository postCategoryRepository,
|
public PostCategoryServiceImpl(PostCategoryRepository postCategoryRepository,
|
||||||
PostRepository postRepository,
|
PostRepository postRepository,
|
||||||
CategoryRepository categoryRepository,
|
|
||||||
OptionService optionService) {
|
OptionService optionService) {
|
||||||
super(postCategoryRepository);
|
super(postCategoryRepository);
|
||||||
this.postCategoryRepository = postCategoryRepository;
|
this.postCategoryRepository = postCategoryRepository;
|
||||||
this.postRepository = postRepository;
|
this.postRepository = postRepository;
|
||||||
this.categoryRepository = categoryRepository;
|
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Autowired
|
||||||
|
public void setCategoryService(CategoryService categoryService) {
|
||||||
|
this.categoryService = categoryService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Category> listCategoriesBy(Integer postId) {
|
public List<Category> listCategoriesBy(Integer postId) {
|
||||||
|
return listCategoriesBy(postId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Category> listCategoriesBy(Integer postId, boolean queryEncryptCategory) {
|
||||||
Assert.notNull(postId, "Post id must not be null");
|
Assert.notNull(postId, "Post id must not be null");
|
||||||
|
|
||||||
// Find all category ids
|
// Find all category ids
|
||||||
Set<Integer> categoryIds = postCategoryRepository.findAllCategoryIdsByPostId(postId);
|
Set<Integer> categoryIds = postCategoryRepository.findAllCategoryIdsByPostId(postId);
|
||||||
|
|
||||||
return categoryRepository.findAllById(categoryIds);
|
return categoryService.listAllByIds(categoryIds, queryEncryptCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Integer, List<Category>> listCategoryListMap(Collection<Integer> postIds) {
|
public Map<Integer, List<Category>> listCategoryListMap(
|
||||||
|
Collection<Integer> postIds, boolean queryEncryptCategory) {
|
||||||
if (CollectionUtils.isEmpty(postIds)) {
|
if (CollectionUtils.isEmpty(postIds)) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
@ -86,7 +100,7 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
ServiceUtils.fetchProperty(postCategories, PostCategory::getCategoryId);
|
ServiceUtils.fetchProperty(postCategories, PostCategory::getCategoryId);
|
||||||
|
|
||||||
// Find all categories
|
// Find all categories
|
||||||
List<Category> categories = categoryRepository.findAllById(categoryIds);
|
List<Category> categories = categoryService.listAllByIds(categoryIds, queryEncryptCategory);
|
||||||
|
|
||||||
// Convert to category map
|
// Convert to category map
|
||||||
Map<Integer, Category> categoryMap = ServiceUtils.convertToMap(categories, Category::getId);
|
Map<Integer, Category> categoryMap = ServiceUtils.convertToMap(categories, Category::getId);
|
||||||
|
@ -124,13 +138,45 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
return postRepository.findAllById(postIds);
|
return postRepository.findAllById(postIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Post> listPostBy(Integer categoryId, Set<PostStatus> status) {
|
||||||
|
Assert.notNull(categoryId, "Category id must not be null");
|
||||||
|
Assert.notNull(status, "Post status must not be null");
|
||||||
|
|
||||||
|
// Find all post ids
|
||||||
|
Set<Integer> postIds = postCategoryRepository
|
||||||
|
.findAllPostIdsByCategoryId(categoryId, status);
|
||||||
|
|
||||||
|
return postRepository.findAllById(postIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Post> listPostBy(String slug, Set<PostStatus> status) {
|
||||||
|
Assert.notNull(slug, "Category slug must not be null");
|
||||||
|
Assert.notNull(status, "Post status must not be null");
|
||||||
|
|
||||||
|
Category category = categoryService.getBySlug(slug);
|
||||||
|
|
||||||
|
if (Objects.isNull(category)) {
|
||||||
|
throw new NotFoundException("查询不到该分类的信息").setErrorData(slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Integer> postsIds = postCategoryRepository
|
||||||
|
.findAllPostIdsByCategoryId(category.getId(), status);
|
||||||
|
|
||||||
|
return postRepository.findAllById(postsIds);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Post> listPostBy(String slug, PostStatus status) {
|
public List<Post> listPostBy(String slug, PostStatus status) {
|
||||||
Assert.notNull(slug, "Category slug must not be null");
|
Assert.notNull(slug, "Category slug must not be null");
|
||||||
Assert.notNull(status, "Post status must not be null");
|
Assert.notNull(status, "Post status must not be null");
|
||||||
|
|
||||||
Category category = categoryRepository.getBySlug(slug)
|
Category category = categoryService.getBySlug(slug);
|
||||||
.orElseThrow(() -> new NotFoundException("查询不到该分类的信息").setErrorData(slug));
|
|
||||||
|
if (Objects.isNull(category)) {
|
||||||
|
throw new NotFoundException("查询不到该分类的信息").setErrorData(slug);
|
||||||
|
}
|
||||||
|
|
||||||
Set<Integer> postsIds =
|
Set<Integer> postsIds =
|
||||||
postCategoryRepository.findAllPostIdsByCategoryId(category.getId(), status);
|
postCategoryRepository.findAllPostIdsByCategoryId(category.getId(), status);
|
||||||
|
@ -155,6 +201,19 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
Assert.notNull(status, "Post status must not be null");
|
Assert.notNull(status, "Post status must not be null");
|
||||||
Assert.notNull(pageable, "Page info must not be null");
|
Assert.notNull(pageable, "Page info must not be null");
|
||||||
|
|
||||||
|
// Find all post ids
|
||||||
|
Set<Integer> postIds = postCategoryRepository
|
||||||
|
.findAllPostIdsByCategoryId(categoryId, status);
|
||||||
|
|
||||||
|
return postRepository.findAllByIdIn(postIds, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<Post> pagePostBy(Integer categoryId, Set<PostStatus> status, Pageable pageable) {
|
||||||
|
Assert.notNull(categoryId, "Category id must not be null");
|
||||||
|
Assert.notNull(status, "Post status must not be null");
|
||||||
|
Assert.notNull(pageable, "Page info must not be null");
|
||||||
|
|
||||||
// Find all post ids
|
// Find all post ids
|
||||||
Set<Integer> postIds =
|
Set<Integer> postIds =
|
||||||
postCategoryRepository.findAllPostIdsByCategoryId(categoryId, status);
|
postCategoryRepository.findAllPostIdsByCategoryId(categoryId, status);
|
||||||
|
@ -245,10 +304,10 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CategoryWithPostCountDTO> listCategoryWithPostCountDto(Sort sort) {
|
public List<CategoryWithPostCountDTO> listCategoryWithPostCountDto(
|
||||||
|
Sort sort, boolean queryEncryptCategory) {
|
||||||
Assert.notNull(sort, "Sort info must not be null");
|
Assert.notNull(sort, "Sort info must not be null");
|
||||||
|
List<Category> categories = categoryService.listAll(sort, queryEncryptCategory);
|
||||||
List<Category> categories = categoryRepository.findAll(sort);
|
|
||||||
|
|
||||||
// Query category post count
|
// Query category post count
|
||||||
Map<Integer, Long> categoryPostCountMap = ServiceUtils
|
Map<Integer, Long> categoryPostCountMap = ServiceUtils
|
||||||
|
@ -284,4 +343,10 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PostCategory> listByCategoryIdList(List<Integer> categoryIdList) {
|
||||||
|
Assert.notEmpty(categoryIdList, "category id list not empty");
|
||||||
|
return postCategoryRepository.findAllByCategoryIdList(categoryIdList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.service.impl;
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -60,6 +61,7 @@ import run.halo.app.model.vo.PostListVO;
|
||||||
import run.halo.app.model.vo.PostMarkdownVO;
|
import run.halo.app.model.vo.PostMarkdownVO;
|
||||||
import run.halo.app.repository.PostRepository;
|
import run.halo.app.repository.PostRepository;
|
||||||
import run.halo.app.repository.base.BasePostRepository;
|
import run.halo.app.repository.base.BasePostRepository;
|
||||||
|
import run.halo.app.service.AuthorizationService;
|
||||||
import run.halo.app.service.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.PostCategoryService;
|
import run.halo.app.service.PostCategoryService;
|
||||||
|
@ -106,6 +108,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
private final AuthorizationService authorizationService;
|
||||||
|
|
||||||
public PostServiceImpl(BasePostRepository<Post> basePostRepository,
|
public PostServiceImpl(BasePostRepository<Post> basePostRepository,
|
||||||
OptionService optionService,
|
OptionService optionService,
|
||||||
PostRepository postRepository,
|
PostRepository postRepository,
|
||||||
|
@ -115,7 +119,8 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
PostCategoryService postCategoryService,
|
PostCategoryService postCategoryService,
|
||||||
PostCommentService postCommentService,
|
PostCommentService postCommentService,
|
||||||
ApplicationEventPublisher eventPublisher,
|
ApplicationEventPublisher eventPublisher,
|
||||||
PostMetaService postMetaService) {
|
PostMetaService postMetaService,
|
||||||
|
AuthorizationService authorizationService) {
|
||||||
super(basePostRepository, optionService);
|
super(basePostRepository, optionService);
|
||||||
this.postRepository = postRepository;
|
this.postRepository = postRepository;
|
||||||
this.tagService = tagService;
|
this.tagService = tagService;
|
||||||
|
@ -126,6 +131,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
this.postMetaService = postMetaService;
|
this.postMetaService = postMetaService;
|
||||||
this.optionService = optionService;
|
this.optionService = optionService;
|
||||||
|
this.authorizationService = authorizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -501,10 +507,16 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PostDetailVO convertToDetailVo(Post post) {
|
public PostDetailVO convertToDetailVo(Post post) {
|
||||||
|
return convertToDetailVo(post, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PostDetailVO convertToDetailVo(Post post, boolean queryEncryptCategory) {
|
||||||
// List tags
|
// List tags
|
||||||
List<Tag> tags = postTagService.listTagsBy(post.getId());
|
List<Tag> tags = postTagService.listTagsBy(post.getId());
|
||||||
// List categories
|
// List categories
|
||||||
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
|
List<Category> categories = postCategoryService
|
||||||
|
.listCategoriesBy(post.getId(), queryEncryptCategory);
|
||||||
// List metas
|
// List metas
|
||||||
List<PostMeta> metas = postMetaService.listBy(post.getId());
|
List<PostMeta> metas = postMetaService.listBy(post.getId());
|
||||||
// Convert to detail vo
|
// Convert to detail vo
|
||||||
|
@ -552,6 +564,11 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<PostListVO> convertToListVo(Page<Post> postPage) {
|
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");
|
Assert.notNull(postPage, "Post page must not be null");
|
||||||
|
|
||||||
List<Post> posts = postPage.getContent();
|
List<Post> posts = postPage.getContent();
|
||||||
|
@ -563,7 +580,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
// Get category list map
|
// Get category list map
|
||||||
Map<Integer, List<Category>> categoryListMap = postCategoryService
|
Map<Integer, List<Category>> categoryListMap = postCategoryService
|
||||||
.listCategoryListMap(postIds);
|
.listCategoryListMap(postIds, queryEncryptCategory);
|
||||||
|
|
||||||
// Get comment count
|
// Get comment count
|
||||||
Map<Integer, Long> commentCountMap = postCommentService.countByPostIds(postIds);
|
Map<Integer, Long> commentCountMap = postCommentService.countByPostIds(postIds);
|
||||||
|
@ -612,6 +629,11 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PostListVO> convertToListVo(List<Post> posts) {
|
public List<PostListVO> convertToListVo(List<Post> posts) {
|
||||||
|
return convertToListVo(posts, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PostListVO> convertToListVo(List<Post> posts, boolean queryEncryptCategory) {
|
||||||
Assert.notNull(posts, "Post page must not be null");
|
Assert.notNull(posts, "Post page must not be null");
|
||||||
|
|
||||||
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
|
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
|
||||||
|
@ -621,7 +643,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
|
|
||||||
// Get category list map
|
// Get category list map
|
||||||
Map<Integer, List<Category>> categoryListMap = postCategoryService
|
Map<Integer, List<Category>> categoryListMap = postCategoryService
|
||||||
.listCategoryListMap(postIds);
|
.listCategoryListMap(postIds, queryEncryptCategory);
|
||||||
|
|
||||||
// Get comment count
|
// Get comment count
|
||||||
Map<Integer, Long> commentCountMap = postCommentService.countByPostIds(postIds);
|
Map<Integer, Long> commentCountMap = postCommentService.countByPostIds(postIds);
|
||||||
|
@ -800,6 +822,24 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
Assert.notNull(post, "Post param must not be null");
|
Assert.notNull(post, "Post param must not be null");
|
||||||
|
|
||||||
// Create or update post
|
// Create or update post
|
||||||
|
Boolean needEncrypt = Optional.ofNullable(categoryIds)
|
||||||
|
.filter(CollectionUtil::isNotEmpty)
|
||||||
|
.map(categoryIdSet -> {
|
||||||
|
for (Integer categoryId : categoryIdSet) {
|
||||||
|
if (categoryService.categoryHasEncrypt(categoryId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).orElse(Boolean.FALSE);
|
||||||
|
|
||||||
|
// if password is not empty or parent category has encrypt, change status to intimate
|
||||||
|
if (post.getStatus() != PostStatus.DRAFT
|
||||||
|
&& (StringUtils.isNotEmpty(post.getPassword()) || needEncrypt)
|
||||||
|
) {
|
||||||
|
post.setStatus(PostStatus.INTIMATE);
|
||||||
|
}
|
||||||
|
|
||||||
post = super.createOrUpdateBy(post);
|
post = super.createOrUpdateBy(post);
|
||||||
|
|
||||||
postTagService.removeByPostId(post.getId());
|
postTagService.removeByPostId(post.getId());
|
||||||
|
@ -810,7 +850,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
List<Tag> tags = tagService.listAllByIds(tagIds);
|
List<Tag> tags = tagService.listAllByIds(tagIds);
|
||||||
|
|
||||||
// List all categories
|
// List all categories
|
||||||
List<Category> categories = categoryService.listAllByIds(categoryIds);
|
List<Category> categories = categoryService.listAllByIds(categoryIds, true);
|
||||||
|
|
||||||
// Create post tags
|
// Create post tags
|
||||||
List<PostTag> postTags = postTagService.mergeOrCreateByIfAbsent(post.getId(),
|
List<PostTag> postTags = postTagService.mergeOrCreateByIfAbsent(post.getId(),
|
||||||
|
@ -830,10 +870,34 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
.createOrUpdateByPostId(post.getId(), metas);
|
.createOrUpdateByPostId(post.getId(), metas);
|
||||||
log.debug("Created post metas: [{}]", postMetaList);
|
log.debug("Created post metas: [{}]", postMetaList);
|
||||||
|
|
||||||
|
// Remove authorization every time an post is created or updated.
|
||||||
|
authorizationService.deletePostAuthorization(post.getId());
|
||||||
|
|
||||||
// Convert to post detail vo
|
// Convert to post detail vo
|
||||||
return convertTo(post, tags, categories, postMetaList);
|
return convertTo(post, tags, categories, postMetaList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Post updateStatus(PostStatus status, Integer postId) {
|
||||||
|
super.updateStatus(status, postId);
|
||||||
|
if (PostStatus.PUBLISHED.equals(status)) {
|
||||||
|
// When the update status is published, it is necessary to determine whether
|
||||||
|
// the post status should be converted to a intimate post
|
||||||
|
categoryService.refreshPostStatus(Collections.singletonList(postId));
|
||||||
|
}
|
||||||
|
return getById(postId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public List<Post> updateStatusByIds(List<Integer> ids, PostStatus status) {
|
||||||
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return ids.stream().map(id -> updateStatus(status, id)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publishVisitEvent(Integer postId) {
|
public void publishVisitEvent(Integer postId) {
|
||||||
eventPublisher.publishEvent(new PostVisitEvent(this, postId));
|
eventPublisher.publishEvent(new PostVisitEvent(this, postId));
|
||||||
|
|
|
@ -152,9 +152,9 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<form method="post" action="${blog_url!}/archives/${slug!}/password">
|
<form method="post" action="${blog_url!}/archives/${type!}/${slug!}/password">
|
||||||
<div class="password-input">
|
<div class="password-input">
|
||||||
<input type="password" name="password" placeholder="请输入文章访问密码">
|
<input type="password" name="password" placeholder="请输入访问密码">
|
||||||
<span class="bottom"></span>
|
<span class="bottom"></span>
|
||||||
<span class="right"></span>
|
<span class="right"></span>
|
||||||
<span class="top"></span>
|
<span class="top"></span>
|
||||||
|
|
Loading…
Reference in New Issue