feat: add more query params and sorter for single page (#2481)

#### 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
```
pull/2493/head
guqing 2022-09-28 23:50:17 +08:00 committed by GitHub
parent 27e151a574
commit 98829f0a3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 161 additions and 4 deletions

View File

@ -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<String> getContributors() {
List<String> 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);
}
}

View File

@ -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<SinglePage, String> 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<SinglePage> 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<SinglePage> from(SinglePageSorter sorter) {
if (sorter == null) {
return defaultComparator();
}
if (CREATE_TIME.equals(sorter)) {
Function<SinglePage, Instant> comparatorFunc =
page -> page.getMetadata().getCreationTimestamp();
return Comparator.comparing(comparatorFunc)
.thenComparing(name);
}
if (PUBLISH_TIME.equals(sorter)) {
Function<SinglePage, Instant> 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<SinglePage> defaultComparator() {
Function<SinglePage, Instant> createTime =
page -> page.getMetadata().getCreationTimestamp();
return Comparator.comparing(createTime)
.thenComparing(name);
}
}

View File

@ -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<SinglePage> 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<ListResult<ListedSinglePage>> list(SinglePageQuery query) {
Comparator<SinglePage> 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<SinglePage> pageListPredicate(SinglePageQuery query) {
Predicate<SinglePage> 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<SinglePage> predicate = labelAndFieldSelectorToPredicate(query.getLabelSelector(),
query.getFieldSelector());
return predicate.and(paramPredicate);

View File

@ -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)