diff --git a/application/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java b/application/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java index 11c592424..2bc65c080 100644 --- a/application/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java +++ b/application/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java @@ -17,6 +17,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -88,12 +89,16 @@ public class CategoryFinderImpl implements CategoryFinder { @Override public Flux listAsTree() { - return this.toCategoryTreeVoFlux(null); + return listAll() + .collectList() + .flatMapMany(list -> Flux.fromIterable(listToTree(list, null))); } @Override public Flux listAsTree(String name) { - return this.toCategoryTreeVoFlux(name); + return listAllFor(name) + .collectList() + .flatMapMany(list -> Flux.fromIterable(listToTree(list, name))); } @Override @@ -103,43 +108,50 @@ public class CategoryFinderImpl implements CategoryFinder { .map(CategoryVo::from); } - Flux listAllFor(String parentName) { - return categoryService.isCategoryHidden(parentName) + private Flux listAllFor(String parentName) { + return Mono.defer( + () -> { + if (StringUtils.isBlank(parentName)) { + return Mono.just(false); + } + return categoryService.isCategoryHidden(parentName); + }) .flatMapMany( isHidden -> client.listAll(Category.class, new ListOptions(), defaultSort()) - .filter(category -> isHidden || !category.getSpec().isHideFromList()) + .filter(category -> { + if (isHidden) { + return true; + } + return !category.getSpec().isHideFromList(); + }) .map(CategoryVo::from) ); } - Flux toCategoryTreeVoFlux(String name) { - return listAllFor(name) - .collectList() - .flatMapIterable(categoryVos -> { - Map nameIdentityMap = categoryVos.stream() - .map(CategoryTreeVo::from) - .collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(), - Function.identity())); + private List listToTree(List categoryVos, @Nullable String name) { + Map nameIdentityMap = categoryVos.stream() + .map(CategoryTreeVo::from) + .collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(), + Function.identity())); - nameIdentityMap.forEach((nameKey, value) -> { - List children = value.getSpec().getChildren(); - if (children == null) { - return; - } - for (String child : children) { - CategoryTreeVo childNode = nameIdentityMap.get(child); - if (childNode != null) { - childNode.setParentName(nameKey); - } - } - }); - var tree = listToTree(nameIdentityMap.values(), name); - recomputePostCount(tree); - return tree; - }); + nameIdentityMap.forEach((nameKey, value) -> { + List children = value.getSpec().getChildren(); + if (children == null) { + return; + } + for (String child : children) { + CategoryTreeVo childNode = nameIdentityMap.get(child); + if (childNode != null) { + childNode.setParentName(nameKey); + } + } + }); + var tree = listToTree(nameIdentityMap.values(), name); + recomputePostCount(tree); + return tree; } - static List listToTree(Collection list, String name) { + private static List listToTree(Collection list, String name) { Map> parentNameIdentityMap = list.stream() .filter(categoryTreeVo -> categoryTreeVo.getParentName() != null) .collect(Collectors.groupingBy(CategoryTreeVo::getParentName)); @@ -228,8 +240,9 @@ public class CategoryFinderImpl implements CategoryFinder { @Override public Flux getBreadcrumbs(String name) { - return listAsTree() + return listAllFor(name) .collectList() + .map(list -> listToTree(list, null)) .flatMapMany(treeNodes -> { var rootNode = dummyVirtualRoot(treeNodes); var paths = new ArrayList(); diff --git a/application/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java b/application/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java index 1e0307871..6f1bbb2a6 100644 --- a/application/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java +++ b/application/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java @@ -13,6 +13,8 @@ import java.time.Instant; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -190,13 +192,13 @@ class CategoryFinderImplTest { var json = Files.readString(file.toPath()); categories = JsonUtils.jsonToObject(json, new TypeReference<>() { }); - when(client.listAll(eq(Category.class), any(ListOptions.class), any(Sort.class))) - .thenReturn(Flux.fromIterable(categories)); } @Test void computePostCountFromTree() { - var treeVos = categoryFinder.toCategoryTreeVoFlux("全部") + when(client.listAll(eq(Category.class), any(ListOptions.class), any(Sort.class))) + .thenReturn(Flux.fromIterable(categories)); + var treeVos = categoryFinder.listAsTree("全部") .collectList().block(); assertThat(treeVos).hasSize(1); String s = visualizeTree(treeVos.get(0).getChildren()); @@ -232,6 +234,8 @@ class CategoryFinderImplTest { @Test void getBreadcrumbsTest() { + when(client.listAll(eq(Category.class), any(ListOptions.class), any(Sort.class))) + .thenReturn(Flux.fromIterable(categories)); // first level var breadcrumbs = categoryFinder.getBreadcrumbs("全部").collectList().block(); assertThat(toNames(breadcrumbs)).containsSequence("全部"); @@ -259,6 +263,26 @@ class CategoryFinderImplTest { assertThat(toNames(breadcrumbs)).isEmpty(); } + @Test + void getBreadcrumbsForHiddenTest() { + Map categoryMap = categories.stream() + .collect( + Collectors.toMap(item -> item.getMetadata().getName(), Function.identity())); + var category = categoryMap.get("IndependentNode"); + category.getSpec().setHideFromList(true); + when(client.listAll(eq(Category.class), any(ListOptions.class), any(Sort.class))) + .thenReturn(Flux.fromIterable(categoryMap.values())); + + when(categoryService.isCategoryHidden(eq("IndependentChild4"))) + .thenReturn(Mono.just(true)); + + var breadcrumbs = categoryFinder.getBreadcrumbs("IndependentChild4") + .collectList().block(); + assertThat(toNames(breadcrumbs)).containsSequence("全部", "FIT2CLOUD", + "IndependentNode", + "IndependentChild4"); + } + static List toNames(List categories) { if (categories == null) { return List.of();