fix: breadcrumbs for hidden category can not be displayed (#6200)

#### What type of PR is this?
/kind bug
/area core
/area theme
/milestone 2.17.x

#### What this PR does / why we need it:
修复获取隐藏分类的面包屑路径不正确的问题

#### Which issue(s) this PR fixes:
Fixes #6197

#### Does this PR introduce a user-facing change?
```release-note
修复获取隐藏分类的面包屑路径不正确的问题
```
pull/6216/head
guqing 2024-06-28 18:02:59 +08:00 committed by GitHub
parent 80e1110da2
commit 4cafdb5a72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 34 deletions

View File

@ -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<CategoryTreeVo> listAsTree() {
return this.toCategoryTreeVoFlux(null);
return listAll()
.collectList()
.flatMapMany(list -> Flux.fromIterable(listToTree(list, null)));
}
@Override
public Flux<CategoryTreeVo> listAsTree(String name) {
return this.toCategoryTreeVoFlux(name);
return listAllFor(name)
.collectList()
.flatMapMany(list -> Flux.fromIterable(listToTree(list, name)));
}
@Override
@ -103,19 +108,27 @@ public class CategoryFinderImpl implements CategoryFinder {
.map(CategoryVo::from);
}
Flux<CategoryVo> listAllFor(String parentName) {
return categoryService.isCategoryHidden(parentName)
private Flux<CategoryVo> 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<CategoryTreeVo> toCategoryTreeVoFlux(String name) {
return listAllFor(name)
.collectList()
.flatMapIterable(categoryVos -> {
private List<CategoryTreeVo> listToTree(List<CategoryVo> categoryVos, @Nullable String name) {
Map<String, CategoryTreeVo> nameIdentityMap = categoryVos.stream()
.map(CategoryTreeVo::from)
.collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(),
@ -136,10 +149,9 @@ public class CategoryFinderImpl implements CategoryFinder {
var tree = listToTree(nameIdentityMap.values(), name);
recomputePostCount(tree);
return tree;
});
}
static List<CategoryTreeVo> listToTree(Collection<CategoryTreeVo> list, String name) {
private static List<CategoryTreeVo> listToTree(Collection<CategoryTreeVo> list, String name) {
Map<String, List<CategoryTreeVo>> 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<CategoryVo> getBreadcrumbs(String name) {
return listAsTree()
return listAllFor(name)
.collectList()
.map(list -> listToTree(list, null))
.flatMapMany(treeNodes -> {
var rootNode = dummyVirtualRoot(treeNodes);
var paths = new ArrayList<CategoryVo>();

View File

@ -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<String, Category> 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<String> toNames(List<CategoryVo> categories) {
if (categories == null) {
return List.of();