From 98829f0a3e2f59e8bbb800e58a0c9b6979ea2af8 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Wed, 28 Sep 2022 23:50:17 +0800 Subject: [PATCH] feat: add more query params and sorter for single page (#2481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind feature /milestone 2.0 /area core /kind api-change #### What this PR does / why we need it: 自定义页面增加排序和筛选: 筛选: 关键词 状态 可见性 作者 排序: 发布时间 创建时间 #### Which issue(s) this PR fixes: Fixes #2469 #### Special notes for your reviewer: /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../run/halo/app/content/SinglePageQuery.java | 38 +++++++++ .../halo/app/content/SinglePageSorter.java | 78 +++++++++++++++++++ .../content/impl/SinglePageServiceImpl.java | 43 +++++++++- .../halo/app/core/extension/SinglePage.java | 6 ++ 4 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 src/main/java/run/halo/app/content/SinglePageSorter.java diff --git a/src/main/java/run/halo/app/content/SinglePageQuery.java b/src/main/java/run/halo/app/content/SinglePageQuery.java index 419968fd0..f0dcb4667 100644 --- a/src/main/java/run/halo/app/content/SinglePageQuery.java +++ b/src/main/java/run/halo/app/content/SinglePageQuery.java @@ -1,9 +1,12 @@ package run.halo.app.content; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; +import run.halo.app.core.extension.Post; import run.halo.app.core.extension.SinglePage; import run.halo.app.extension.router.IListRequest; @@ -20,8 +23,43 @@ public class SinglePageQuery extends IListRequest.QueryListRequest { } @Nullable + @Schema(name = "contributor") public Set getContributors() { List contributorList = queryParams.get("contributor"); return contributorList == null ? null : Set.copyOf(contributorList); } + + @Nullable + public Post.PostPhase getPublishPhase() { + String publishPhase = queryParams.getFirst("publishPhase"); + return Post.PostPhase.from(publishPhase); + } + + @Nullable + public Post.VisibleEnum getVisible() { + String visible = queryParams.getFirst("visible"); + return Post.VisibleEnum.from(visible); + } + + @Nullable + @Schema(description = "SinglePages filtered by keyword.") + public String getKeyword() { + return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null); + } + + @Schema(description = "SinglePage collation.") + public SinglePageSorter getSort() { + String sort = queryParams.getFirst("sort"); + return SinglePageSorter.convertFrom(sort); + } + + @Schema(description = "ascending order If it is true; otherwise, it is in descending order.") + public Boolean getSortOrder() { + String sortOrder = queryParams.getFirst("sortOrder"); + return convertBooleanOrNull(sortOrder); + } + + private Boolean convertBooleanOrNull(String value) { + return StringUtils.isBlank(value) ? null : Boolean.parseBoolean(value); + } } diff --git a/src/main/java/run/halo/app/content/SinglePageSorter.java b/src/main/java/run/halo/app/content/SinglePageSorter.java new file mode 100644 index 000000000..4bdbbb624 --- /dev/null +++ b/src/main/java/run/halo/app/content/SinglePageSorter.java @@ -0,0 +1,78 @@ +package run.halo.app.content; + +import java.time.Instant; +import java.util.Comparator; +import java.util.Objects; +import java.util.function.Function; +import org.springframework.util.comparator.Comparators; +import run.halo.app.core.extension.SinglePage; + +/** + * A sorter for {@link SinglePage}. + * + * @author guqing + * @since 2.0.0 + */ +public enum SinglePageSorter { + PUBLISH_TIME, + CREATE_TIME; + + static final Function name = page -> page.getMetadata().getName(); + + /** + * Converts {@link Comparator} from {@link SinglePageSorter} and ascending. + * + * @param sorter a {@link SinglePageSorter} + * @param ascending ascending if true, otherwise descending + * @return a {@link Comparator} of {@link SinglePage} + */ + public static Comparator from(SinglePageSorter sorter, Boolean ascending) { + if (Objects.equals(true, ascending)) { + return from(sorter); + } + return from(sorter).reversed(); + } + + /** + * Converts {@link Comparator} from {@link SinglePageSorter}. + * + * @param sorter a {@link SinglePageSorter} + * @return a {@link Comparator} of {@link SinglePage} + */ + public static Comparator from(SinglePageSorter sorter) { + if (sorter == null) { + return defaultComparator(); + } + if (CREATE_TIME.equals(sorter)) { + Function comparatorFunc = + page -> page.getMetadata().getCreationTimestamp(); + return Comparator.comparing(comparatorFunc) + .thenComparing(name); + } + + if (PUBLISH_TIME.equals(sorter)) { + Function comparatorFunc = + page -> page.getSpec().getPublishTime(); + return Comparator.comparing(comparatorFunc, Comparators.nullsLow()) + .thenComparing(name); + } + + throw new IllegalArgumentException("Unsupported sort value: " + sorter); + } + + static SinglePageSorter convertFrom(String sort) { + for (SinglePageSorter sorter : values()) { + if (sorter.name().equalsIgnoreCase(sort)) { + return sorter; + } + } + return null; + } + + static Comparator defaultComparator() { + Function createTime = + page -> page.getMetadata().getCreationTimestamp(); + return Comparator.comparing(createTime) + .thenComparing(name); + } +} diff --git a/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java b/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java index bc91c385e..2d98c2be0 100644 --- a/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java +++ b/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; +import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Service; @@ -22,6 +23,7 @@ import run.halo.app.content.ListedSinglePage; import run.halo.app.content.SinglePageQuery; import run.halo.app.content.SinglePageRequest; import run.halo.app.content.SinglePageService; +import run.halo.app.content.SinglePageSorter; import run.halo.app.core.extension.Post; import run.halo.app.core.extension.SinglePage; import run.halo.app.core.extension.Snapshot; @@ -39,9 +41,6 @@ import run.halo.app.infra.ConditionStatus; */ @Service public class SinglePageServiceImpl implements SinglePageService { - private static final Comparator DEFAULT_PAGE_COMPARATOR = - Comparator.comparing(page -> page.getMetadata().getCreationTimestamp()); - private final ContentService contentService; private final ReactiveExtensionClient client; @@ -53,8 +52,10 @@ public class SinglePageServiceImpl implements SinglePageService { @Override public Mono> list(SinglePageQuery query) { + Comparator comparator = + SinglePageSorter.from(query.getSort(), query.getSortOrder()); return client.list(SinglePage.class, pageListPredicate(query), - DEFAULT_PAGE_COMPARATOR.reversed(), query.getPage(), query.getSize()) + comparator, query.getPage(), query.getSize()) .flatMap(listResult -> Flux.fromStream( listResult.get().map(this::getListedSinglePage) ) @@ -133,6 +134,40 @@ public class SinglePageServiceImpl implements SinglePageService { Predicate pageListPredicate(SinglePageQuery query) { Predicate paramPredicate = singlePage -> contains(query.getContributors(), singlePage.getStatusOrDefault().getContributors()); + + String keyword = query.getKeyword(); + if (keyword != null) { + paramPredicate = paramPredicate.and(page -> { + String excerpt = page.getStatusOrDefault().getExcerpt(); + return StringUtils.containsIgnoreCase(excerpt, keyword) + || StringUtils.containsIgnoreCase(page.getSpec().getSlug(), keyword) + || StringUtils.containsIgnoreCase(page.getSpec().getTitle(), keyword); + }); + } + + Post.PostPhase publishPhase = query.getPublishPhase(); + if (publishPhase != null) { + paramPredicate = paramPredicate.and(page -> { + if (Post.PostPhase.PENDING_APPROVAL.equals(publishPhase)) { + return !page.isPublished() + && Post.PostPhase.PENDING_APPROVAL.name() + .equalsIgnoreCase(page.getStatusOrDefault().getPhase()); + } + // published + if (Post.PostPhase.PUBLISHED.equals(publishPhase)) { + return page.isPublished(); + } + // draft + return !page.isPublished(); + }); + } + + Post.VisibleEnum visible = query.getVisible(); + if (visible != null) { + paramPredicate = + paramPredicate.and(post -> visible.equals(post.getSpec().getVisible())); + } + Predicate predicate = labelAndFieldSelectorToPredicate(query.getLabelSelector(), query.getFieldSelector()); return predicate.and(paramPredicate); diff --git a/src/main/java/run/halo/app/core/extension/SinglePage.java b/src/main/java/run/halo/app/core/extension/SinglePage.java index bf94489a2..944f20bb2 100644 --- a/src/main/java/run/halo/app/core/extension/SinglePage.java +++ b/src/main/java/run/halo/app/core/extension/SinglePage.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.Instant; import java.util.List; import java.util.Map; +import java.util.Objects; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -43,6 +44,11 @@ public class SinglePage extends AbstractExtension { return this.status; } + @JsonIgnore + public boolean isPublished() { + return Objects.equals(true, spec.getPublished()); + } + @Data public static class SinglePageSpec { @Schema(required = true, minLength = 1)