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 code
pull/1820/head
guqing 2022-04-04 11:40:41 +08:00 committed by GitHub
parent 1de5799f82
commit 90d1bce9b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 79 deletions

View File

@ -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;
}
}

View File

@ -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.
*

View File

@ -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);
}

View File

@ -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);
}
}