From 5a7e794feaf4d0e7436b85f59ef83c5618268119 Mon Sep 17 00:00:00 2001 From: Takagi <1103069291@qq.com> Date: Thu, 20 Jul 2023 15:28:17 +0800 Subject: [PATCH] feat: allow attachment library to filter certain groups and their attachments (#4255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind feature /area core #### What this PR does / why we need it: 为附件库增加过滤条件,过滤 labels 中包含 `halo.run/hidden` 的分组及其附件。 #### Which issue(s) this PR fixes: Fixes #4251 #### Special notes for your reviewer: 保证默认情况下附件能够正常访问即可。 或者为分组增加 `halo.run/hidden` label,之后查看接口中是否不包含具有目标分组及其附件。 #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../app/core/extension/attachment/Group.java | 1 + .../endpoint/AttachmentEndpoint.java | 32 +++++++++--- .../endpoint/AttachmentEndpointTest.java | 49 +++++++++++++++++++ .../composables/use-attachment-group.ts | 6 ++- 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/run/halo/app/core/extension/attachment/Group.java b/api/src/main/java/run/halo/app/core/extension/attachment/Group.java index 8a6d40985..d3b743110 100644 --- a/api/src/main/java/run/halo/app/core/extension/attachment/Group.java +++ b/api/src/main/java/run/halo/app/core/extension/attachment/Group.java @@ -18,6 +18,7 @@ import run.halo.app.extension.GVK; public class Group extends AbstractExtension { public static final String KIND = "Group"; + public static final String HIDDEN_LABEL = "halo.run/hidden"; @Schema(required = true) private GroupSpec spec; diff --git a/application/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java b/application/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java index dbebf1a93..af0c4855b 100644 --- a/application/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java +++ b/application/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpoint.java @@ -37,10 +37,12 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; import reactor.core.publisher.Mono; import run.halo.app.core.extension.attachment.Attachment; +import run.halo.app.core.extension.attachment.Group; import run.halo.app.core.extension.endpoint.CustomEndpoint; import run.halo.app.core.extension.endpoint.SortResolver; import run.halo.app.core.extension.service.AttachmentService; import run.halo.app.extension.Comparators; +import run.halo.app.extension.MetadataUtil; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.router.IListRequest; import run.halo.app.extension.router.IListRequest.QueryListRequest; @@ -104,12 +106,30 @@ public class AttachmentEndpoint implements CustomEndpoint { Mono search(ServerRequest request) { var searchRequest = new SearchRequest(request); - return client.list(Attachment.class, - searchRequest.toPredicate(), searchRequest.toComparator(), - searchRequest.getPage(), searchRequest.getSize()) - .flatMap(listResult -> ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .bodyValue(listResult)); + return client.list(Group.class, group -> MetadataUtil.nullSafeLabels(group) + .containsKey(Group.HIDDEN_LABEL), null) + .map(group -> group.getMetadata().getName()) + .collectList() + .defaultIfEmpty(List.of()) + .flatMap(groups -> client.list(Attachment.class, + searchRequest.toPredicate().and(visibleGroupPredicate(groups)), + searchRequest.toComparator(), + searchRequest.getPage(), searchRequest.getSize()) + .flatMap(listResult -> ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(listResult) + ) + ); + + } + + static Predicate visibleGroupPredicate(List hiddenGroups) { + return attachment -> { + if (!StringUtils.hasText(attachment.getSpec().getGroupName())) { + return true; + } + return !hiddenGroups.contains(attachment.getSpec().getGroupName()); + }; } public interface ISearchRequest extends IListRequest { diff --git a/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java b/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java index e23f5176f..873065269 100644 --- a/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java +++ b/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java @@ -1,9 +1,11 @@ package run.halo.app.core.extension.attachment.endpoint; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -15,6 +17,7 @@ import static org.springframework.security.test.web.reactive.server.SecurityMock import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Predicate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -28,9 +31,11 @@ import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.BodyInserters; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.core.extension.attachment.Attachment; import run.halo.app.core.extension.attachment.Attachment.AttachmentSpec; +import run.halo.app.core.extension.attachment.Group; import run.halo.app.core.extension.attachment.Policy; import run.halo.app.core.extension.attachment.Policy.PolicySpec; import run.halo.app.core.extension.attachment.endpoint.AttachmentEndpoint.SearchRequest; @@ -236,6 +241,9 @@ class AttachmentEndpointTest { @Test void shouldListUngroupedAttachments() { + when(client.list(eq(Group.class), any(), any())) + .thenReturn(Flux.empty()); + when(client.list(same(Attachment.class), any(), any(), anyInt(), anyInt())) .thenReturn(Mono.just(ListResult.emptyResult())); @@ -270,6 +278,47 @@ class AttachmentEndpointTest { spec.setGroupName("halo"); assertFalse(pred.test(attachment)); } + + @Test + void searchAttachmentWhenGroupIsEmpty() { + when(client.list(eq(Group.class), any(), any())) + .thenReturn(Flux.empty()); + + when(client.list(eq(Attachment.class), any(), any(), anyInt(), anyInt())) + .thenReturn(Mono.empty()); + + webClient + .get() + .uri("/attachments") + .exchange() + .expectStatus().isOk(); + + verify(client).list(eq(Attachment.class), any(), any(), anyInt(), anyInt()); + } + } + + @Test + void visibleGroupPredicate() { + Predicate noHiddenGroupPredicate = + AttachmentEndpoint.visibleGroupPredicate(List.of()); + + Attachment attachment = mock(Attachment.class); + AttachmentSpec spec = mock(AttachmentSpec.class); + when(attachment.getSpec()).thenReturn(spec); + + when(spec.getGroupName()).thenReturn(""); + assertThat(noHiddenGroupPredicate.test(attachment)).isTrue(); + + when(spec.getGroupName()).thenReturn("test"); + assertThat(noHiddenGroupPredicate.test(attachment)).isTrue(); + + Predicate hasHiddenGroupPredicate = + AttachmentEndpoint.visibleGroupPredicate(List.of("hidden-group")); + when(spec.getGroupName()).thenReturn("fake"); + assertThat(hasHiddenGroupPredicate.test(attachment)).isTrue(); + + when(spec.getGroupName()).thenReturn("hidden-group"); + assertThat(hasHiddenGroupPredicate.test(attachment)).isFalse(); } } \ No newline at end of file diff --git a/console/src/modules/contents/attachments/composables/use-attachment-group.ts b/console/src/modules/contents/attachments/composables/use-attachment-group.ts index 1b1a77aa7..aff2a23fd 100644 --- a/console/src/modules/contents/attachments/composables/use-attachment-group.ts +++ b/console/src/modules/contents/attachments/composables/use-attachment-group.ts @@ -14,7 +14,11 @@ export function useFetchAttachmentGroup(): useFetchAttachmentGroupReturn { queryKey: ["attachment-groups"], queryFn: async () => { const { data } = - await apiClient.extension.storage.group.liststorageHaloRunV1alpha1Group(); + await apiClient.extension.storage.group.liststorageHaloRunV1alpha1Group( + { + labelSelector: ["!halo.run/hidden"], + } + ); return data.items; }, refetchInterval(data) {