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;
|
package run.halo.app.event.category;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import run.halo.app.model.entity.Category;
|
import run.halo.app.model.entity.Category;
|
||||||
|
@ -15,13 +16,15 @@ public class CategoryUpdatedEvent extends ApplicationEvent {
|
||||||
private final Category beforeUpdated;
|
private final Category beforeUpdated;
|
||||||
private final Category category;
|
private final Category category;
|
||||||
private final boolean beforeIsPrivate;
|
private final boolean beforeIsPrivate;
|
||||||
|
private final Set<Integer> postIds;
|
||||||
|
|
||||||
public CategoryUpdatedEvent(Object source, Category category,
|
public CategoryUpdatedEvent(Object source, Category category,
|
||||||
Category beforeUpdated, boolean beforeIsPrivate) {
|
Category beforeUpdated, boolean beforeIsPrivate, Set<Integer> postIds) {
|
||||||
super(source);
|
super(source);
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.beforeUpdated = beforeUpdated;
|
this.beforeUpdated = beforeUpdated;
|
||||||
this.beforeIsPrivate = beforeIsPrivate;
|
this.beforeIsPrivate = beforeIsPrivate;
|
||||||
|
this.postIds = postIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -37,4 +40,8 @@ public class CategoryUpdatedEvent extends ApplicationEvent {
|
||||||
public boolean isBeforeIsPrivate() {
|
public boolean isBeforeIsPrivate() {
|
||||||
return beforeIsPrivate;
|
return beforeIsPrivate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getPostIds() {
|
||||||
|
return postIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
package run.halo.app.listener.post;
|
package run.halo.app.listener.post;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import run.halo.app.event.category.CategoryUpdatedEvent;
|
import run.halo.app.event.category.CategoryUpdatedEvent;
|
||||||
import run.halo.app.event.post.PostUpdatedEvent;
|
import run.halo.app.event.post.PostUpdatedEvent;
|
||||||
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.PostCategory;
|
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
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;
|
||||||
import run.halo.app.utils.ServiceUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post status management.
|
* Post status management.
|
||||||
|
@ -53,45 +48,55 @@ public class PostRefreshStatusListener {
|
||||||
Category beforeUpdated = event.getBeforeUpdated();
|
Category beforeUpdated = event.getBeforeUpdated();
|
||||||
boolean beforeIsPrivate = event.isBeforeIsPrivate();
|
boolean beforeIsPrivate = event.isBeforeIsPrivate();
|
||||||
RecordState recordState = determineRecordState(beforeUpdated, category);
|
RecordState recordState = determineRecordState(beforeUpdated, category);
|
||||||
|
|
||||||
|
List<Post> posts = postService.listAllByIds(event.getPostIds());
|
||||||
|
|
||||||
|
// handle delete action
|
||||||
if (RecordState.DELETED.equals(recordState) || category == null) {
|
if (RecordState.DELETED.equals(recordState) || category == null) {
|
||||||
|
if (beforeUpdated == null || !beforeIsPrivate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Cancel the encryption status of the posts
|
||||||
|
changeStatusToPublishIfNecessary(posts, beforeUpdated.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now
|
// now
|
||||||
boolean isPrivate = categoryService.isPrivate(category.getId());
|
boolean isPrivate = categoryService.isPrivate(category.getId());
|
||||||
List<Post> posts = findPostsByCategoryIdRecursively(category.getId());
|
|
||||||
if (isPrivate) {
|
if (isPrivate) {
|
||||||
|
List<Post> postsToUpdate = new ArrayList<>();
|
||||||
posts.forEach(post -> {
|
posts.forEach(post -> {
|
||||||
if (post.getStatus() == PostStatus.PUBLISHED) {
|
if (post.getStatus() == PostStatus.PUBLISHED) {
|
||||||
post.setStatus(PostStatus.INTIMATE);
|
post.setStatus(PostStatus.INTIMATE);
|
||||||
|
postsToUpdate.add(post);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
postService.updateInBatch(postsToUpdate);
|
||||||
if (RecordState.UPDATED.equals(recordState)) {
|
} else if (beforeIsPrivate && RecordState.UPDATED.equals(recordState)) {
|
||||||
Set<Integer> encryptedCategories =
|
// Cancel the encryption status of the posts
|
||||||
pickUpEncryptedFromUpdatedRecord(category.getId());
|
changeStatusToPublishIfNecessary(posts, 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(posts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean postBelongsToEncryptedCategory(Integer postId,
|
private void changeStatusToPublishIfNecessary(List<Post> posts, Integer categoryId) {
|
||||||
Set<Integer> encryptedCategories) {
|
List<Post> postsToUpdate = new ArrayList<>();
|
||||||
Set<Integer> categoryIds =
|
for (Post post : posts) {
|
||||||
postCategoryService.listCategoryIdsByPostId(postId);
|
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;
|
boolean encrypted = false;
|
||||||
for (Integer categoryId : categoryIds) {
|
for (Integer categoryId : categoryIds) {
|
||||||
if (encryptedCategories.contains(categoryId)) {
|
if (categoryService.isPrivate(categoryId)) {
|
||||||
encrypted = true;
|
encrypted = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -99,40 +104,6 @@ public class PostRefreshStatusListener {
|
||||||
return encrypted;
|
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) {
|
private RecordState determineRecordState(Category before, Category updated) {
|
||||||
if (before == null) {
|
if (before == null) {
|
||||||
if (updated != null) {
|
if (updated != null) {
|
||||||
|
@ -153,27 +124,16 @@ public class PostRefreshStatusListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* effective state for database record.
|
|
||||||
*/
|
|
||||||
enum RecordState {
|
enum RecordState {
|
||||||
|
/**
|
||||||
|
* effective state for database record.
|
||||||
|
*/
|
||||||
CREATED,
|
CREATED,
|
||||||
UPDATED,
|
UPDATED,
|
||||||
DELETED,
|
DELETED,
|
||||||
UNCHANGED
|
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.
|
* 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.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
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.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
@ -133,4 +134,13 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
||||||
* @return a tree of category.
|
* @return a tree of category.
|
||||||
*/
|
*/
|
||||||
List<CategoryVO> listToTree(List<Category> categories);
|
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 static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -28,6 +29,7 @@ import run.halo.app.exception.AlreadyExistsException;
|
||||||
import run.halo.app.exception.NotFoundException;
|
import run.halo.app.exception.NotFoundException;
|
||||||
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.PostCategory;
|
||||||
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.CategoryService;
|
import run.halo.app.service.CategoryService;
|
||||||
|
@ -111,8 +113,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
boolean beforeIsPrivate = isPrivate(category.getId());
|
boolean beforeIsPrivate = isPrivate(category.getId());
|
||||||
|
|
||||||
Category updated = super.update(category);
|
Category updated = super.update(category);
|
||||||
|
|
||||||
|
Set<Integer> postIds = listPostIdsByCategoryIdRecursively(category.getId());
|
||||||
applicationContext.publishEvent(
|
applicationContext.publishEvent(
|
||||||
new CategoryUpdatedEvent(this, category, beforeUpdated, beforeIsPrivate));
|
new CategoryUpdatedEvent(this, category, beforeUpdated, beforeIsPrivate, postIds));
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,8 +187,10 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void removeCategoryAndPostCategoryBy(Integer categoryId) {
|
public void removeCategoryAndPostCategoryBy(Integer categoryId) {
|
||||||
|
final boolean beforeIsPrivate = isPrivate(categoryId);
|
||||||
|
final Set<Integer> postIds = listPostIdsByCategoryIdRecursively(categoryId);
|
||||||
List<Category> categories = listByParentId(categoryId);
|
List<Category> categories = listByParentId(categoryId);
|
||||||
if (null != categories && categories.size() > 0) {
|
if (null != categories && categories.size() > 0) {
|
||||||
categories.forEach(category -> {
|
categories.forEach(category -> {
|
||||||
|
@ -198,7 +204,8 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
// Remove post categories
|
// Remove post categories
|
||||||
postCategoryService.removeByCategoryId(categoryId);
|
postCategoryService.removeByCategoryId(categoryId);
|
||||||
|
|
||||||
applicationContext.publishEvent(new CategoryUpdatedEvent(this, null, category, false));
|
applicationContext.publishEvent(
|
||||||
|
new CategoryUpdatedEvent(this, null, category, beforeIsPrivate, postIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -371,12 +378,26 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
||||||
Category categoryParam = idCategoryParamMap.get(categoryToUpdate.getId());
|
Category categoryParam = idCategoryParamMap.get(categoryToUpdate.getId());
|
||||||
BeanUtils.updateProperties(categoryParam, categoryToUpdate);
|
BeanUtils.updateProperties(categoryParam, categoryToUpdate);
|
||||||
Category categoryUpdated = update(categoryToUpdate);
|
Category categoryUpdated = update(categoryToUpdate);
|
||||||
|
|
||||||
|
Set<Integer> postIds = listPostIdsByCategoryIdRecursively(categoryUpdated.getId());
|
||||||
applicationContext.publishEvent(new CategoryUpdatedEvent(this,
|
applicationContext.publishEvent(new CategoryUpdatedEvent(this,
|
||||||
categoryUpdated, categoryBefore, beforeIsPrivate));
|
categoryUpdated, categoryBefore, beforeIsPrivate, postIds));
|
||||||
return categoryUpdated;
|
return categoryUpdated;
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.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