mirror of https://github.com/halo-dev/halo
feat: allow attachment library to filter certain groups and their attachments (#4255)
#### 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 ```pull/4270/head
parent
d21472dc0f
commit
5a7e794fea
|
@ -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;
|
||||
|
|
|
@ -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<ServerResponse> 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<Attachment> visibleGroupPredicate(List<String> hiddenGroups) {
|
||||
return attachment -> {
|
||||
if (!StringUtils.hasText(attachment.getSpec().getGroupName())) {
|
||||
return true;
|
||||
}
|
||||
return !hiddenGroups.contains(attachment.getSpec().getGroupName());
|
||||
};
|
||||
}
|
||||
|
||||
public interface ISearchRequest extends IListRequest {
|
||||
|
|
|
@ -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<Attachment> 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<Attachment> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue