mirror of https://github.com/halo-dev/halo
fix: update the posts encryption status synchronously after deleting the category (#1815)
* refactor: update the posts encryption status synchronously after deleting the category * chore: delete unused codepull/1820/head
parent
1de5799f82
commit
90d1bce9b9
|
@ -1,5 +1,6 @@
|
|||
package run.halo.app.event.category;
|
||||
|
||||
import java.util.Set;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.lang.Nullable;
|
||||
import run.halo.app.model.entity.Category;
|
||||
|
@ -15,13 +16,15 @@ public class CategoryUpdatedEvent extends ApplicationEvent {
|
|||
private final Category beforeUpdated;
|
||||
private final Category category;
|
||||
private final boolean beforeIsPrivate;
|
||||
private final Set<Integer> postIds;
|
||||
|
||||
public CategoryUpdatedEvent(Object source, Category category,
|
||||
Category beforeUpdated, boolean beforeIsPrivate) {
|
||||
Category beforeUpdated, boolean beforeIsPrivate, Set<Integer> postIds) {
|
||||
super(source);
|
||||
this.category = category;
|
||||
this.beforeUpdated = beforeUpdated;
|
||||
this.beforeIsPrivate = beforeIsPrivate;
|
||||
this.postIds = postIds;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -37,4 +40,8 @@ public class CategoryUpdatedEvent extends ApplicationEvent {
|
|||
public boolean isBeforeIsPrivate() {
|
||||
return beforeIsPrivate;
|
||||
}
|
||||
|
||||
public Set<Integer> getPostIds() {
|
||||
return postIds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
package run.halo.app.listener.post;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.event.category.CategoryUpdatedEvent;
|
||||
import run.halo.app.event.post.PostUpdatedEvent;
|
||||
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.service.CategoryService;
|
||||
import run.halo.app.service.PostCategoryService;
|
||||
import run.halo.app.service.PostService;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
||||
/**
|
||||
* Post status management.
|
||||
|
@ -53,45 +48,55 @@ public class PostRefreshStatusListener {
|
|||
Category beforeUpdated = event.getBeforeUpdated();
|
||||
boolean beforeIsPrivate = event.isBeforeIsPrivate();
|
||||
RecordState recordState = determineRecordState(beforeUpdated, category);
|
||||
|
||||
List<Post> posts = postService.listAllByIds(event.getPostIds());
|
||||
|
||||
// handle delete action
|
||||
if (RecordState.DELETED.equals(recordState) || category == null) {
|
||||
if (beforeUpdated == null || !beforeIsPrivate) {
|
||||
return;
|
||||
}
|
||||
// Cancel the encryption status of the posts
|
||||
changeStatusToPublishIfNecessary(posts, beforeUpdated.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// now
|
||||
boolean isPrivate = categoryService.isPrivate(category.getId());
|
||||
List<Post> posts = findPostsByCategoryIdRecursively(category.getId());
|
||||
if (isPrivate) {
|
||||
List<Post> postsToUpdate = new ArrayList<>();
|
||||
posts.forEach(post -> {
|
||||
if (post.getStatus() == PostStatus.PUBLISHED) {
|
||||
post.setStatus(PostStatus.INTIMATE);
|
||||
postsToUpdate.add(post);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (RecordState.UPDATED.equals(recordState)) {
|
||||
Set<Integer> encryptedCategories =
|
||||
pickUpEncryptedFromUpdatedRecord(category.getId());
|
||||
for (Post post : posts) {
|
||||
boolean belongsToEncryptedCategory =
|
||||
postBelongsToEncryptedCategory(post.getId(), encryptedCategories);
|
||||
if (!belongsToEncryptedCategory && StringUtils.isBlank(post.getPassword())
|
||||
&& beforeIsPrivate
|
||||
&& post.getStatus() == PostStatus.INTIMATE) {
|
||||
post.setStatus(PostStatus.PUBLISHED);
|
||||
}
|
||||
}
|
||||
}
|
||||
postService.updateInBatch(postsToUpdate);
|
||||
} else if (beforeIsPrivate && RecordState.UPDATED.equals(recordState)) {
|
||||
// Cancel the encryption status of the posts
|
||||
changeStatusToPublishIfNecessary(posts, category.getId());
|
||||
}
|
||||
postService.updateInBatch(posts);
|
||||
}
|
||||
|
||||
private boolean postBelongsToEncryptedCategory(Integer postId,
|
||||
Set<Integer> encryptedCategories) {
|
||||
Set<Integer> categoryIds =
|
||||
postCategoryService.listCategoryIdsByPostId(postId);
|
||||
private void changeStatusToPublishIfNecessary(List<Post> posts, Integer categoryId) {
|
||||
List<Post> postsToUpdate = new ArrayList<>();
|
||||
for (Post post : posts) {
|
||||
boolean belongsToEncryptedCategory = postBelongsToEncryptedCategory(post.getId());
|
||||
if (!belongsToEncryptedCategory && StringUtils.isBlank(post.getPassword())
|
||||
&& post.getStatus() == PostStatus.INTIMATE) {
|
||||
post.setStatus(PostStatus.PUBLISHED);
|
||||
postsToUpdate.add(post);
|
||||
}
|
||||
}
|
||||
postService.updateInBatch(postsToUpdate);
|
||||
}
|
||||
|
||||
private boolean postBelongsToEncryptedCategory(Integer postId) {
|
||||
Set<Integer> categoryIds = postCategoryService.listCategoryIdsByPostId(postId);
|
||||
|
||||
boolean encrypted = false;
|
||||
for (Integer categoryId : categoryIds) {
|
||||
if (encryptedCategories.contains(categoryId)) {
|
||||
if (categoryService.isPrivate(categoryId)) {
|
||||
encrypted = true;
|
||||
break;
|
||||
}
|
||||
|
@ -99,40 +104,6 @@ public class PostRefreshStatusListener {
|
|||
return encrypted;
|
||||
}
|
||||
|
||||
private Set<Integer> pickUpEncryptedFromUpdatedRecord(Integer categoryId) {
|
||||
Set<Integer> privateCategories = new HashSet<>();
|
||||
|
||||
List<Category> categories = categoryService.listAllByParentId(categoryId);
|
||||
Map<Integer, Category> categoryMap =
|
||||
ServiceUtils.convertToMap(categories, Category::getId);
|
||||
categories.forEach(category -> {
|
||||
boolean privateBy = isPrivateBy(category.getId(), categoryMap);
|
||||
if (privateBy) {
|
||||
privateCategories.add(category.getId());
|
||||
}
|
||||
});
|
||||
return privateCategories;
|
||||
}
|
||||
|
||||
private boolean isPrivateBy(Integer categoryId, Map<Integer, Category> categoryMap) {
|
||||
return findFirstEncryptedCategoryBy(categoryMap, categoryId) != null;
|
||||
}
|
||||
|
||||
private Category findFirstEncryptedCategoryBy(Map<Integer, Category> idToCategoryMap,
|
||||
Integer categoryId) {
|
||||
Category category = idToCategoryMap.get(categoryId);
|
||||
|
||||
if (categoryId == 0 || category == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(category.getPassword())) {
|
||||
return category;
|
||||
}
|
||||
|
||||
return findFirstEncryptedCategoryBy(idToCategoryMap, category.getParentId());
|
||||
}
|
||||
|
||||
private RecordState determineRecordState(Category before, Category updated) {
|
||||
if (before == null) {
|
||||
if (updated != null) {
|
||||
|
@ -153,27 +124,16 @@ public class PostRefreshStatusListener {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* effective state for database record.
|
||||
*/
|
||||
enum RecordState {
|
||||
/**
|
||||
* effective state for database record.
|
||||
*/
|
||||
CREATED,
|
||||
UPDATED,
|
||||
DELETED,
|
||||
UNCHANGED
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Post> findPostsByCategoryIdRecursively(Integer categoryId) {
|
||||
Set<Integer> categoryIds =
|
||||
ServiceUtils.fetchProperty(categoryService.listAllByParentId(categoryId),
|
||||
Category::getId);
|
||||
List<PostCategory> postCategories =
|
||||
postCategoryService.listByCategoryIdList(new ArrayList<>(categoryIds));
|
||||
Set<Integer> postIds = ServiceUtils.fetchProperty(postCategories, PostCategory::getPostId);
|
||||
return postService.listAllByIds(postIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the post belongs to any encryption category, set the status to INTIMATE.
|
||||
*
|
||||
|
|
|
@ -2,6 +2,7 @@ package run.halo.app.service;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
@ -133,4 +134,13 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
|||
* @return a tree of category.
|
||||
*/
|
||||
List<CategoryVO> listToTree(List<Category> categories);
|
||||
|
||||
/**
|
||||
* Recursively query the associated post ids according to the category id.
|
||||
*
|
||||
* @param categoryId category id
|
||||
* @return a collection of post ids
|
||||
*/
|
||||
@NonNull
|
||||
Set<Integer> listPostIdsByCategoryIdRecursively(@NonNull Integer categoryId);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.service.impl;
|
|||
import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
@ -28,6 +29,7 @@ import run.halo.app.exception.AlreadyExistsException;
|
|||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.model.dto.CategoryDTO;
|
||||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.PostCategory;
|
||||
import run.halo.app.model.vo.CategoryVO;
|
||||
import run.halo.app.repository.CategoryRepository;
|
||||
import run.halo.app.service.CategoryService;
|
||||
|
@ -111,8 +113,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
boolean beforeIsPrivate = isPrivate(category.getId());
|
||||
|
||||
Category updated = super.update(category);
|
||||
|
||||
Set<Integer> postIds = listPostIdsByCategoryIdRecursively(category.getId());
|
||||
applicationContext.publishEvent(
|
||||
new CategoryUpdatedEvent(this, category, beforeUpdated, beforeIsPrivate));
|
||||
new CategoryUpdatedEvent(this, category, beforeUpdated, beforeIsPrivate, postIds));
|
||||
return updated;
|
||||
}
|
||||
|
||||
|
@ -183,8 +187,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeCategoryAndPostCategoryBy(Integer categoryId) {
|
||||
final boolean beforeIsPrivate = isPrivate(categoryId);
|
||||
final Set<Integer> postIds = listPostIdsByCategoryIdRecursively(categoryId);
|
||||
List<Category> categories = listByParentId(categoryId);
|
||||
if (null != categories && categories.size() > 0) {
|
||||
categories.forEach(category -> {
|
||||
|
@ -198,7 +204,8 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
// Remove post categories
|
||||
postCategoryService.removeByCategoryId(categoryId);
|
||||
|
||||
applicationContext.publishEvent(new CategoryUpdatedEvent(this, null, category, false));
|
||||
applicationContext.publishEvent(
|
||||
new CategoryUpdatedEvent(this, null, category, beforeIsPrivate, postIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -371,12 +378,26 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
Category categoryParam = idCategoryParamMap.get(categoryToUpdate.getId());
|
||||
BeanUtils.updateProperties(categoryParam, categoryToUpdate);
|
||||
Category categoryUpdated = update(categoryToUpdate);
|
||||
|
||||
Set<Integer> postIds = listPostIdsByCategoryIdRecursively(categoryUpdated.getId());
|
||||
applicationContext.publishEvent(new CategoryUpdatedEvent(this,
|
||||
categoryUpdated, categoryBefore, beforeIsPrivate));
|
||||
categoryUpdated, categoryBefore, beforeIsPrivate, postIds));
|
||||
return categoryUpdated;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Set<Integer> listPostIdsByCategoryIdRecursively(@NonNull Integer categoryId) {
|
||||
Set<Integer> categoryIds = ServiceUtils.fetchProperty(listAllByParentId(categoryId),
|
||||
Category::getId);
|
||||
if (CollectionUtils.isEmpty(categoryIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
List<PostCategory> postCategories =
|
||||
postCategoryService.listByCategoryIdList(new ArrayList<>(categoryIds));
|
||||
return ServiceUtils.fetchProperty(postCategories, PostCategory::getPostId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue