mirror of https://github.com/halo-dev/halo
refactor: sorting parameters to maintain a unified API style (#3956)
#### What type of PR is this? /kind improvement /area core /area console /kind api-change /milestone 2.6.x #### What this PR does / why we need it: 重构排序参数以统一自定义 APIs 的风格 - 文章的排序参数字段名改为 `creationTimestamp`、`publishTime` 查询参数示例为 sort=creationTimestamp,desc - 自定义页面排序参数字段名同文章 - 评论排序参数字段名为 `creationTimestamp`,`replyCount`,`lastReplyTime` 查询参数示例为 sort=creationTimestamp,desc 需要 Console 适配 #### Which issue(s) this PR fixes: Fixes #3464 #### Does this PR introduce a user-facing change? ```release-note 重构排序参数以统一自定义 APIs 的风格 ```pull/3963/head
parent
a6c923d83d
commit
d5f6dc2207
|
@ -1,12 +1,24 @@
|
|||
package run.halo.app.content;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.content.Post;
|
||||
import run.halo.app.core.extension.endpoint.SortResolver;
|
||||
import run.halo.app.extension.Comparators;
|
||||
import run.halo.app.extension.router.IListRequest;
|
||||
|
||||
/**
|
||||
|
@ -17,8 +29,11 @@ import run.halo.app.extension.router.IListRequest;
|
|||
*/
|
||||
public class PostQuery extends IListRequest.QueryListRequest {
|
||||
|
||||
public PostQuery(MultiValueMap<String, String> queryParams) {
|
||||
super(queryParams);
|
||||
private final ServerWebExchange exchange;
|
||||
|
||||
public PostQuery(ServerRequest request) {
|
||||
super(request.queryParams());
|
||||
this.exchange = request.exchange();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -57,16 +72,15 @@ public class PostQuery extends IListRequest.QueryListRequest {
|
|||
return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null);
|
||||
}
|
||||
|
||||
@Schema(description = "Post collation.")
|
||||
public PostSorter getSort() {
|
||||
String sort = queryParams.getFirst("sort");
|
||||
return PostSorter.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);
|
||||
@ArraySchema(uniqueItems = true,
|
||||
arraySchema = @Schema(name = "sort",
|
||||
description = "Sort property and direction of the list result. Supported fields: "
|
||||
+ "creationTimestamp,publishTime"),
|
||||
schema = @Schema(description = "like field,asc or field,desc",
|
||||
implementation = String.class,
|
||||
example = "creationTimestamp,desc"))
|
||||
public Sort getSort() {
|
||||
return SortResolver.defaultInstance.resolve(exchange);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -74,7 +88,104 @@ public class PostQuery extends IListRequest.QueryListRequest {
|
|||
return param == null ? null : Set.copyOf(param);
|
||||
}
|
||||
|
||||
private Boolean convertBooleanOrNull(String value) {
|
||||
return StringUtils.isBlank(value) ? null : Boolean.parseBoolean(value);
|
||||
/**
|
||||
* Build a comparator from the query object.
|
||||
*
|
||||
* @return a comparator
|
||||
*/
|
||||
public Comparator<Post> toComparator() {
|
||||
var sort = getSort();
|
||||
var creationTimestampOrder = sort.getOrderFor("creationTimestamp");
|
||||
List<Comparator<Post>> comparators = new ArrayList<>();
|
||||
if (creationTimestampOrder != null) {
|
||||
Comparator<Post> comparator =
|
||||
comparing(post -> post.getMetadata().getCreationTimestamp());
|
||||
if (creationTimestampOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
|
||||
var publishTimeOrder = sort.getOrderFor("publishTime");
|
||||
if (publishTimeOrder != null) {
|
||||
Comparator<Object> nullsComparator = publishTimeOrder.isAscending()
|
||||
? org.springframework.util.comparator.Comparators.nullsLow()
|
||||
: org.springframework.util.comparator.Comparators.nullsHigh();
|
||||
Comparator<Post> comparator =
|
||||
comparing(post -> post.getSpec().getPublishTime(), nullsComparator);
|
||||
if (publishTimeOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
comparators.add(Comparators.compareCreationTimestamp(false));
|
||||
comparators.add(Comparators.compareName(true));
|
||||
return comparators.stream()
|
||||
.reduce(Comparator::thenComparing)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a predicate from the query object.
|
||||
*
|
||||
* @return a predicate
|
||||
*/
|
||||
public Predicate<Post> toPredicate() {
|
||||
Predicate<Post> paramPredicate = post ->
|
||||
contains(getCategories(), post.getSpec().getCategories())
|
||||
&& contains(getTags(), post.getSpec().getTags())
|
||||
&& contains(getContributors(), post.getStatusOrDefault().getContributors());
|
||||
|
||||
String keyword = getKeyword();
|
||||
if (keyword != null) {
|
||||
paramPredicate = paramPredicate.and(post -> {
|
||||
String excerpt = post.getStatusOrDefault().getExcerpt();
|
||||
return StringUtils.containsIgnoreCase(excerpt, keyword)
|
||||
|| StringUtils.containsIgnoreCase(post.getSpec().getSlug(), keyword)
|
||||
|| StringUtils.containsIgnoreCase(post.getSpec().getTitle(), keyword);
|
||||
});
|
||||
}
|
||||
|
||||
Post.PostPhase publishPhase = getPublishPhase();
|
||||
if (publishPhase != null) {
|
||||
paramPredicate = paramPredicate.and(post -> {
|
||||
if (Post.PostPhase.PENDING_APPROVAL.equals(publishPhase)) {
|
||||
return !post.isPublished()
|
||||
&& Post.PostPhase.PENDING_APPROVAL.name()
|
||||
.equalsIgnoreCase(post.getStatusOrDefault().getPhase());
|
||||
}
|
||||
// published
|
||||
if (Post.PostPhase.PUBLISHED.equals(publishPhase)) {
|
||||
return post.isPublished();
|
||||
}
|
||||
// draft
|
||||
return !post.isPublished();
|
||||
});
|
||||
}
|
||||
|
||||
Post.VisibleEnum visible = getVisible();
|
||||
if (visible != null) {
|
||||
paramPredicate =
|
||||
paramPredicate.and(post -> visible.equals(post.getSpec().getVisible()));
|
||||
}
|
||||
|
||||
Predicate<Post> predicate = labelAndFieldSelectorToPredicate(getLabelSelector(),
|
||||
getFieldSelector());
|
||||
return predicate.and(paramPredicate);
|
||||
}
|
||||
|
||||
boolean contains(Collection<String> left, List<String> right) {
|
||||
// parameter is null, it means that ignore this condition
|
||||
if (left == null) {
|
||||
return true;
|
||||
}
|
||||
// else, it means that right is empty
|
||||
if (left.isEmpty()) {
|
||||
return right.isEmpty();
|
||||
}
|
||||
if (right == null) {
|
||||
return false;
|
||||
}
|
||||
return right.stream().anyMatch(left::contains);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
package run.halo.app.content;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.content.Post;
|
||||
import run.halo.app.core.extension.content.SinglePage;
|
||||
import run.halo.app.core.extension.endpoint.SortResolver;
|
||||
import run.halo.app.extension.Comparators;
|
||||
import run.halo.app.extension.router.IListRequest;
|
||||
|
||||
/**
|
||||
|
@ -18,8 +30,11 @@ import run.halo.app.extension.router.IListRequest;
|
|||
*/
|
||||
public class SinglePageQuery extends IListRequest.QueryListRequest {
|
||||
|
||||
public SinglePageQuery(MultiValueMap<String, String> queryParams) {
|
||||
super(queryParams);
|
||||
private final ServerWebExchange exchange;
|
||||
|
||||
public SinglePageQuery(ServerRequest request) {
|
||||
super(request.queryParams());
|
||||
this.exchange = request.exchange();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -47,19 +62,113 @@ public class SinglePageQuery extends IListRequest.QueryListRequest {
|
|||
return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null);
|
||||
}
|
||||
|
||||
@Schema(description = "SinglePage collation.")
|
||||
public SinglePageSorter getSort() {
|
||||
String sort = queryParams.getFirst("sort");
|
||||
return SinglePageSorter.convertFrom(sort);
|
||||
@ArraySchema(uniqueItems = true,
|
||||
arraySchema = @Schema(name = "sort",
|
||||
description = "Sort property and direction of the list result. Supported fields: "
|
||||
+ "creationTimestamp,publishTime"),
|
||||
schema = @Schema(description = "like field,asc or field,desc",
|
||||
implementation = String.class,
|
||||
example = "creationTimestamp,desc"))
|
||||
public Sort getSort() {
|
||||
return SortResolver.defaultInstance.resolve(exchange);
|
||||
}
|
||||
|
||||
@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);
|
||||
/**
|
||||
* Build a comparator for {@link SinglePageQuery}.
|
||||
*
|
||||
* @return comparator
|
||||
*/
|
||||
public Comparator<SinglePage> toComparator() {
|
||||
var sort = getSort();
|
||||
var creationTimestampOrder = sort.getOrderFor("creationTimestamp");
|
||||
List<Comparator<SinglePage>> comparators = new ArrayList<>();
|
||||
if (creationTimestampOrder != null) {
|
||||
Comparator<SinglePage> comparator =
|
||||
comparing(page -> page.getMetadata().getCreationTimestamp());
|
||||
if (creationTimestampOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
|
||||
var publishTimeOrder = sort.getOrderFor("publishTime");
|
||||
if (publishTimeOrder != null) {
|
||||
Comparator<Object> nullsComparator = publishTimeOrder.isAscending()
|
||||
? org.springframework.util.comparator.Comparators.nullsLow()
|
||||
: org.springframework.util.comparator.Comparators.nullsHigh();
|
||||
Comparator<SinglePage> comparator =
|
||||
comparing(page -> page.getSpec().getPublishTime(), nullsComparator);
|
||||
if (publishTimeOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
comparators.add(Comparators.compareCreationTimestamp(false));
|
||||
comparators.add(Comparators.compareName(true));
|
||||
return comparators.stream()
|
||||
.reduce(Comparator::thenComparing)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private Boolean convertBooleanOrNull(String value) {
|
||||
return StringUtils.isBlank(value) ? null : Boolean.parseBoolean(value);
|
||||
/**
|
||||
* Build a predicate for {@link SinglePageQuery}.
|
||||
*
|
||||
* @return predicate
|
||||
*/
|
||||
public Predicate<SinglePage> toPredicate() {
|
||||
Predicate<SinglePage> paramPredicate = singlePage -> contains(getContributors(),
|
||||
singlePage.getStatusOrDefault().getContributors());
|
||||
|
||||
String keyword = 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 = 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 = getVisible();
|
||||
if (visible != null) {
|
||||
paramPredicate =
|
||||
paramPredicate.and(post -> visible.equals(post.getSpec().getVisible()));
|
||||
}
|
||||
|
||||
Predicate<SinglePage> predicate = labelAndFieldSelectorToPredicate(getLabelSelector(),
|
||||
getFieldSelector());
|
||||
return predicate.and(paramPredicate);
|
||||
}
|
||||
|
||||
boolean contains(Collection<String> left, List<String> right) {
|
||||
// parameter is null, it means that ignore this condition
|
||||
if (left == null) {
|
||||
return true;
|
||||
}
|
||||
// else, it means that right is empty
|
||||
if (left.isEmpty()) {
|
||||
return right.isEmpty();
|
||||
}
|
||||
if (right == null) {
|
||||
return false;
|
||||
}
|
||||
return right.stream().anyMatch(left::contains);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
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.content.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);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,28 @@
|
|||
package run.halo.app.content.comment;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.content.Comment;
|
||||
import run.halo.app.core.extension.endpoint.SortResolver;
|
||||
import run.halo.app.extension.Comparators;
|
||||
import run.halo.app.extension.Extension;
|
||||
import run.halo.app.extension.Ref;
|
||||
import run.halo.app.extension.router.IListRequest;
|
||||
|
||||
/**
|
||||
|
@ -13,8 +33,17 @@ import run.halo.app.extension.router.IListRequest;
|
|||
*/
|
||||
public class CommentQuery extends IListRequest.QueryListRequest {
|
||||
|
||||
public CommentQuery(MultiValueMap<String, String> queryParams) {
|
||||
super(queryParams);
|
||||
private final ServerWebExchange exchange;
|
||||
static final Function<Comment, Instant> LAST_REPLY_TIME_FUNC =
|
||||
comment -> {
|
||||
Instant lastReplyTime = comment.getStatusOrDefault().getLastReplyTime();
|
||||
return Optional.ofNullable(lastReplyTime)
|
||||
.orElse(comment.getSpec().getCreationTime());
|
||||
};
|
||||
|
||||
public CommentQuery(ServerRequest request) {
|
||||
super(request.queryParams());
|
||||
this.exchange = request.exchange();
|
||||
}
|
||||
|
||||
@Schema(description = "Comments filtered by keyword.")
|
||||
|
@ -67,16 +96,144 @@ public class CommentQuery extends IListRequest.QueryListRequest {
|
|||
return StringUtils.isBlank(subjectName) ? null : subjectName;
|
||||
}
|
||||
|
||||
@Schema(description = "Comment collation.")
|
||||
public CommentSorter getSort() {
|
||||
String sort = queryParams.getFirst("sort");
|
||||
return CommentSorter.convertFrom(sort);
|
||||
@ArraySchema(uniqueItems = true,
|
||||
arraySchema = @Schema(name = "sort",
|
||||
description = "Sort property and direction of the list result. Supported fields: "
|
||||
+ "creationTimestamp,replyCount,lastReplyTime"),
|
||||
schema = @Schema(description = "like field,asc or field,desc",
|
||||
implementation = String.class,
|
||||
example = "creationTimestamp,desc"))
|
||||
public Sort getSort() {
|
||||
return SortResolver.defaultInstance.resolve(exchange);
|
||||
}
|
||||
|
||||
@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);
|
||||
/**
|
||||
* Build a comparator from the query.
|
||||
*
|
||||
* @return comparator
|
||||
*/
|
||||
public Comparator<Comment> toComparator() {
|
||||
var sort = getSort();
|
||||
var creationTimestampOrder = sort.getOrderFor("creationTimestamp");
|
||||
List<Comparator<Comment>> comparators = new ArrayList<>();
|
||||
if (creationTimestampOrder != null) {
|
||||
Comparator<Comment> comparator =
|
||||
comparing(comment -> comment.getMetadata().getCreationTimestamp());
|
||||
if (creationTimestampOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
|
||||
var replyCountOrder = sort.getOrderFor("replyCount");
|
||||
if (replyCountOrder != null) {
|
||||
Comparator<Comment> comparator = comparing(
|
||||
comment -> defaultIfNull(comment.getStatusOrDefault().getReplyCount(), 0));
|
||||
if (replyCountOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
}
|
||||
|
||||
var lastReplyTimeOrder = sort.getOrderFor("lastReplyTime");
|
||||
if (lastReplyTimeOrder == null) {
|
||||
lastReplyTimeOrder = new Sort.Order(Sort.Direction.DESC, "lastReplyTime");
|
||||
}
|
||||
Comparator<Comment> comparator = comparing(LAST_REPLY_TIME_FUNC,
|
||||
Comparators.nullsComparator(lastReplyTimeOrder.isAscending()));
|
||||
if (lastReplyTimeOrder.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
comparators.add(comparator);
|
||||
comparators.add(Comparators.compareCreationTimestamp(false));
|
||||
comparators.add(Comparators.compareName(true));
|
||||
return comparators.stream()
|
||||
.reduce(Comparator::thenComparing)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a predicate from the query.
|
||||
*
|
||||
* @return predicate
|
||||
*/
|
||||
Predicate<Comment> toPredicate() {
|
||||
Predicate<Comment> predicate = comment -> true;
|
||||
|
||||
String keyword = getKeyword();
|
||||
if (keyword != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
String raw = comment.getSpec().getRaw();
|
||||
return StringUtils.containsIgnoreCase(raw, keyword);
|
||||
});
|
||||
}
|
||||
|
||||
Boolean approved = getApproved();
|
||||
if (approved != null) {
|
||||
predicate =
|
||||
predicate.and(comment -> Objects.equals(comment.getSpec().getApproved(), approved));
|
||||
}
|
||||
Boolean hidden = getHidden();
|
||||
if (hidden != null) {
|
||||
predicate =
|
||||
predicate.and(comment -> Objects.equals(comment.getSpec().getHidden(), hidden));
|
||||
}
|
||||
|
||||
Boolean top = getTop();
|
||||
if (top != null) {
|
||||
predicate = predicate.and(comment -> Objects.equals(comment.getSpec().getTop(), top));
|
||||
}
|
||||
|
||||
Boolean allowNotification = getAllowNotification();
|
||||
if (allowNotification != null) {
|
||||
predicate = predicate.and(
|
||||
comment -> Objects.equals(comment.getSpec().getAllowNotification(),
|
||||
allowNotification));
|
||||
}
|
||||
|
||||
String ownerKind = getOwnerKind();
|
||||
if (ownerKind != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Comment.CommentOwner owner = comment.getSpec().getOwner();
|
||||
return Objects.equals(owner.getKind(), ownerKind);
|
||||
});
|
||||
}
|
||||
|
||||
String ownerName = getOwnerName();
|
||||
if (ownerName != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Comment.CommentOwner owner = comment.getSpec().getOwner();
|
||||
if (Comment.CommentOwner.KIND_EMAIL.equals(owner.getKind())) {
|
||||
return Objects.equals(owner.getKind(), ownerKind)
|
||||
&& (StringUtils.containsIgnoreCase(owner.getName(), ownerName)
|
||||
|| StringUtils.containsIgnoreCase(owner.getDisplayName(), ownerName));
|
||||
}
|
||||
return Objects.equals(owner.getKind(), ownerKind)
|
||||
&& StringUtils.containsIgnoreCase(owner.getName(), ownerName);
|
||||
});
|
||||
}
|
||||
|
||||
String subjectKind = getSubjectKind();
|
||||
if (subjectKind != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Ref subjectRef = comment.getSpec().getSubjectRef();
|
||||
return Objects.equals(subjectRef.getKind(), subjectKind);
|
||||
});
|
||||
}
|
||||
|
||||
String subjectName = getSubjectName();
|
||||
if (subjectName != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Ref subjectRef = comment.getSpec().getSubjectRef();
|
||||
return Objects.equals(subjectRef.getKind(), subjectKind)
|
||||
&& StringUtils.containsIgnoreCase(subjectRef.getName(), subjectName);
|
||||
});
|
||||
}
|
||||
|
||||
Predicate<Extension> labelAndFieldSelectorPredicate =
|
||||
labelAndFieldSelectorToPredicate(getLabelSelector(),
|
||||
getFieldSelector());
|
||||
return predicate.and(labelAndFieldSelectorPredicate);
|
||||
}
|
||||
|
||||
private Boolean convertBooleanOrNull(String value) {
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
package run.halo.app.content.comment;
|
||||
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
@ -56,10 +50,8 @@ public class CommentServiceImpl implements CommentService {
|
|||
|
||||
@Override
|
||||
public Mono<ListResult<ListedComment>> listComment(CommentQuery commentQuery) {
|
||||
Comparator<Comment> comparator =
|
||||
CommentSorter.from(commentQuery.getSort(), commentQuery.getSortOrder());
|
||||
return this.client.list(Comment.class, commentPredicate(commentQuery),
|
||||
comparator,
|
||||
return this.client.list(Comment.class, commentQuery.toPredicate(),
|
||||
commentQuery.toComparator(),
|
||||
commentQuery.getPage(), commentQuery.getSize())
|
||||
.flatMap(comments -> Flux.fromStream(comments.get()
|
||||
.map(this::toListedComment))
|
||||
|
@ -200,83 +192,4 @@ public class CommentServiceImpl implements CommentService {
|
|||
.map(commentSubject -> commentSubject.get(ref.getName()))
|
||||
.orElseGet(Mono::empty);
|
||||
}
|
||||
|
||||
Predicate<Comment> commentPredicate(CommentQuery query) {
|
||||
Predicate<Comment> predicate = comment -> true;
|
||||
|
||||
String keyword = query.getKeyword();
|
||||
if (keyword != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
String raw = comment.getSpec().getRaw();
|
||||
return StringUtils.containsIgnoreCase(raw, keyword);
|
||||
});
|
||||
}
|
||||
|
||||
Boolean approved = query.getApproved();
|
||||
if (approved != null) {
|
||||
predicate =
|
||||
predicate.and(comment -> Objects.equals(comment.getSpec().getApproved(), approved));
|
||||
}
|
||||
Boolean hidden = query.getHidden();
|
||||
if (hidden != null) {
|
||||
predicate =
|
||||
predicate.and(comment -> Objects.equals(comment.getSpec().getHidden(), hidden));
|
||||
}
|
||||
|
||||
Boolean top = query.getTop();
|
||||
if (top != null) {
|
||||
predicate = predicate.and(comment -> Objects.equals(comment.getSpec().getTop(), top));
|
||||
}
|
||||
|
||||
Boolean allowNotification = query.getAllowNotification();
|
||||
if (allowNotification != null) {
|
||||
predicate = predicate.and(
|
||||
comment -> Objects.equals(comment.getSpec().getAllowNotification(),
|
||||
allowNotification));
|
||||
}
|
||||
|
||||
String ownerKind = query.getOwnerKind();
|
||||
if (ownerKind != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Comment.CommentOwner owner = comment.getSpec().getOwner();
|
||||
return Objects.equals(owner.getKind(), ownerKind);
|
||||
});
|
||||
}
|
||||
|
||||
String ownerName = query.getOwnerName();
|
||||
if (ownerName != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Comment.CommentOwner owner = comment.getSpec().getOwner();
|
||||
if (Comment.CommentOwner.KIND_EMAIL.equals(owner.getKind())) {
|
||||
return Objects.equals(owner.getKind(), ownerKind)
|
||||
&& (StringUtils.containsIgnoreCase(owner.getName(), ownerName)
|
||||
|| StringUtils.containsIgnoreCase(owner.getDisplayName(), ownerName));
|
||||
}
|
||||
return Objects.equals(owner.getKind(), ownerKind)
|
||||
&& StringUtils.containsIgnoreCase(owner.getName(), ownerName);
|
||||
});
|
||||
}
|
||||
|
||||
String subjectKind = query.getSubjectKind();
|
||||
if (subjectKind != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Ref subjectRef = comment.getSpec().getSubjectRef();
|
||||
return Objects.equals(subjectRef.getKind(), subjectKind);
|
||||
});
|
||||
}
|
||||
|
||||
String subjectName = query.getSubjectName();
|
||||
if (subjectName != null) {
|
||||
predicate = predicate.and(comment -> {
|
||||
Ref subjectRef = comment.getSpec().getSubjectRef();
|
||||
return Objects.equals(subjectRef.getKind(), subjectKind)
|
||||
&& StringUtils.containsIgnoreCase(subjectRef.getName(), subjectName);
|
||||
});
|
||||
}
|
||||
|
||||
Predicate<Extension> labelAndFieldSelectorPredicate =
|
||||
labelAndFieldSelectorToPredicate(query.getLabelSelector(),
|
||||
query.getFieldSelector());
|
||||
return predicate.and(labelAndFieldSelectorPredicate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package run.halo.app.content.comment;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import org.springframework.util.comparator.Comparators;
|
||||
import run.halo.app.core.extension.content.Comment;
|
||||
|
||||
/**
|
||||
* Comment sorter.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum CommentSorter {
|
||||
LAST_REPLY_TIME,
|
||||
REPLY_COUNT,
|
||||
CREATE_TIME;
|
||||
|
||||
static final Function<Comment, String> name = comment -> comment.getMetadata().getName();
|
||||
|
||||
static Comparator<Comment> from(CommentSorter sorter, Boolean ascending) {
|
||||
if (Objects.equals(true, ascending)) {
|
||||
return from(sorter);
|
||||
}
|
||||
return from(sorter).reversed();
|
||||
}
|
||||
|
||||
static Comparator<Comment> from(CommentSorter sorter) {
|
||||
if (sorter == null) {
|
||||
return lastReplyTimeComparator();
|
||||
}
|
||||
if (CREATE_TIME.equals(sorter)) {
|
||||
Function<Comment, Instant> comparatorFunc =
|
||||
comment -> comment.getSpec().getCreationTime();
|
||||
return Comparator.comparing(comparatorFunc, Comparators.nullsLow())
|
||||
.thenComparing(name);
|
||||
}
|
||||
|
||||
if (REPLY_COUNT.equals(sorter)) {
|
||||
Function<Comment, Integer> comparatorFunc =
|
||||
comment -> comment.getStatusOrDefault().getReplyCount();
|
||||
return Comparator.comparing(comparatorFunc, Comparators.nullsLow())
|
||||
.thenComparing(name);
|
||||
}
|
||||
|
||||
if (LAST_REPLY_TIME.equals(sorter)) {
|
||||
Function<Comment, Instant> comparatorFunc =
|
||||
comment -> comment.getStatusOrDefault().getLastReplyTime();
|
||||
return Comparator.comparing(comparatorFunc, Comparators.nullsLow())
|
||||
.thenComparing(name);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Unsupported sort value: " + sorter);
|
||||
}
|
||||
|
||||
static CommentSorter convertFrom(String sort) {
|
||||
for (CommentSorter sorter : values()) {
|
||||
if (sorter.name().equalsIgnoreCase(sort)) {
|
||||
return sorter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Comparator<Comment> lastReplyTimeComparator() {
|
||||
Function<Comment, Instant> comparatorFunc =
|
||||
comment -> {
|
||||
Instant lastReplyTime = comment.getStatusOrDefault().getLastReplyTime();
|
||||
return Optional.ofNullable(lastReplyTime)
|
||||
.orElse(comment.getSpec().getCreationTime());
|
||||
};
|
||||
return Comparator.comparing(comparatorFunc, Comparators.nullsLow())
|
||||
.thenComparing(name);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,10 @@
|
|||
package run.halo.app.content.impl;
|
||||
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
|
@ -26,7 +21,6 @@ import run.halo.app.content.ListedPost;
|
|||
import run.halo.app.content.PostQuery;
|
||||
import run.halo.app.content.PostRequest;
|
||||
import run.halo.app.content.PostService;
|
||||
import run.halo.app.content.PostSorter;
|
||||
import run.halo.app.content.Stats;
|
||||
import run.halo.app.core.extension.content.Category;
|
||||
import run.halo.app.core.extension.content.Post;
|
||||
|
@ -63,10 +57,8 @@ public class PostServiceImpl extends AbstractContentService implements PostServi
|
|||
|
||||
@Override
|
||||
public Mono<ListResult<ListedPost>> listPost(PostQuery query) {
|
||||
Comparator<Post> comparator =
|
||||
PostSorter.from(query.getSort(), query.getSortOrder());
|
||||
return client.list(Post.class, postListPredicate(query),
|
||||
comparator, query.getPage(), query.getSize())
|
||||
return client.list(Post.class, query.toPredicate(),
|
||||
query.toComparator(), query.getPage(), query.getSize())
|
||||
.flatMap(listResult -> Flux.fromStream(
|
||||
listResult.get().map(this::getListedPost)
|
||||
)
|
||||
|
@ -92,65 +84,6 @@ public class PostServiceImpl extends AbstractContentService implements PostServi
|
|||
.defaultIfEmpty(Stats.empty());
|
||||
}
|
||||
|
||||
Predicate<Post> postListPredicate(PostQuery query) {
|
||||
Predicate<Post> paramPredicate = post ->
|
||||
contains(query.getCategories(), post.getSpec().getCategories())
|
||||
&& contains(query.getTags(), post.getSpec().getTags())
|
||||
&& contains(query.getContributors(), post.getStatusOrDefault().getContributors());
|
||||
|
||||
String keyword = query.getKeyword();
|
||||
if (keyword != null) {
|
||||
paramPredicate = paramPredicate.and(post -> {
|
||||
String excerpt = post.getStatusOrDefault().getExcerpt();
|
||||
return StringUtils.containsIgnoreCase(excerpt, keyword)
|
||||
|| StringUtils.containsIgnoreCase(post.getSpec().getSlug(), keyword)
|
||||
|| StringUtils.containsIgnoreCase(post.getSpec().getTitle(), keyword);
|
||||
});
|
||||
}
|
||||
|
||||
Post.PostPhase publishPhase = query.getPublishPhase();
|
||||
if (publishPhase != null) {
|
||||
paramPredicate = paramPredicate.and(post -> {
|
||||
if (Post.PostPhase.PENDING_APPROVAL.equals(publishPhase)) {
|
||||
return !post.isPublished()
|
||||
&& Post.PostPhase.PENDING_APPROVAL.name()
|
||||
.equalsIgnoreCase(post.getStatusOrDefault().getPhase());
|
||||
}
|
||||
// published
|
||||
if (Post.PostPhase.PUBLISHED.equals(publishPhase)) {
|
||||
return post.isPublished();
|
||||
}
|
||||
// draft
|
||||
return !post.isPublished();
|
||||
});
|
||||
}
|
||||
|
||||
Post.VisibleEnum visible = query.getVisible();
|
||||
if (visible != null) {
|
||||
paramPredicate =
|
||||
paramPredicate.and(post -> visible.equals(post.getSpec().getVisible()));
|
||||
}
|
||||
|
||||
Predicate<Post> predicate = labelAndFieldSelectorToPredicate(query.getLabelSelector(),
|
||||
query.getFieldSelector());
|
||||
return predicate.and(paramPredicate);
|
||||
}
|
||||
|
||||
boolean contains(Collection<String> left, List<String> right) {
|
||||
// parameter is null, it means that ignore this condition
|
||||
if (left == null) {
|
||||
return true;
|
||||
}
|
||||
// else, it means that right is empty
|
||||
if (left.isEmpty()) {
|
||||
return right.isEmpty();
|
||||
}
|
||||
if (right == null) {
|
||||
return false;
|
||||
}
|
||||
return right.stream().anyMatch(left::contains);
|
||||
}
|
||||
|
||||
private Mono<ListedPost> getListedPost(Post post) {
|
||||
Assert.notNull(post, "The post must not be null.");
|
||||
return Mono.just(post)
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
package run.halo.app.content.impl;
|
||||
|
||||
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToPredicate;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
|
@ -26,7 +21,6 @@ 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.content.Stats;
|
||||
import run.halo.app.core.extension.content.Post;
|
||||
import run.halo.app.core.extension.content.SinglePage;
|
||||
|
@ -81,10 +75,8 @@ public class SinglePageServiceImpl extends AbstractContentService implements Sin
|
|||
|
||||
@Override
|
||||
public Mono<ListResult<ListedSinglePage>> list(SinglePageQuery query) {
|
||||
Comparator<SinglePage> comparator =
|
||||
SinglePageSorter.from(query.getSort(), query.getSortOrder());
|
||||
return client.list(SinglePage.class, pageListPredicate(query),
|
||||
comparator, query.getPage(), query.getSize())
|
||||
return client.list(SinglePage.class, query.toPredicate(),
|
||||
query.toComparator(), query.getPage(), query.getSize())
|
||||
.flatMap(listResult -> Flux.fromStream(
|
||||
listResult.get().map(this::getListedSinglePage)
|
||||
)
|
||||
|
@ -176,48 +168,6 @@ public class SinglePageServiceImpl extends AbstractContentService implements Sin
|
|||
.filter(throwable -> throwable instanceof OptimisticLockingFailureException));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private Mono<ListedSinglePage> getListedSinglePage(SinglePage singlePage) {
|
||||
Assert.notNull(singlePage, "The singlePage must not be null.");
|
||||
return Mono.just(singlePage)
|
||||
|
@ -285,19 +235,4 @@ public class SinglePageServiceImpl extends AbstractContentService implements Sin
|
|||
return contributor;
|
||||
});
|
||||
}
|
||||
|
||||
boolean contains(Collection<String> left, List<String> right) {
|
||||
// parameter is null, it means that ignore this condition
|
||||
if (left == null) {
|
||||
return true;
|
||||
}
|
||||
// else, it means that right is empty
|
||||
if (left.isEmpty()) {
|
||||
return right.isEmpty();
|
||||
}
|
||||
if (right == null) {
|
||||
return false;
|
||||
}
|
||||
return right.stream().anyMatch(left::contains);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ public class CommentEndpoint implements CustomEndpoint {
|
|||
}
|
||||
|
||||
Mono<ServerResponse> listComments(ServerRequest request) {
|
||||
CommentQuery commentQuery = new CommentQuery(request.queryParams());
|
||||
CommentQuery commentQuery = new CommentQuery(request);
|
||||
return commentService.listComment(commentQuery)
|
||||
.flatMap(listedComments -> ServerResponse.ok().bodyValue(listedComments));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import lombok.AllArgsConstructor;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.fn.builders.schema.Builder;
|
||||
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.retry.RetryException;
|
||||
|
@ -49,8 +48,6 @@ public class PostEndpoint implements CustomEndpoint {
|
|||
private final PostService postService;
|
||||
private final ReactiveExtensionClient client;
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public RouterFunction<ServerResponse> endpoint() {
|
||||
final var tag = "api.console.halo.run/v1alpha1/Post";
|
||||
|
@ -277,7 +274,7 @@ public class PostEndpoint implements CustomEndpoint {
|
|||
}
|
||||
|
||||
Mono<ServerResponse> listPost(ServerRequest request) {
|
||||
PostQuery postQuery = new PostQuery(request.queryParams());
|
||||
PostQuery postQuery = new PostQuery(request);
|
||||
return postService.listPost(postQuery)
|
||||
.flatMap(listedPosts -> ServerResponse.ok().bodyValue(listedPosts));
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ public class SinglePageEndpoint implements CustomEndpoint {
|
|||
}
|
||||
|
||||
Mono<ServerResponse> listSinglePage(ServerRequest request) {
|
||||
var listRequest = new SinglePageQuery(request.queryParams());
|
||||
var listRequest = new SinglePageQuery(request);
|
||||
return singlePageService.list(listRequest)
|
||||
.flatMap(listedPages -> ServerResponse.ok().bodyValue(listedPages));
|
||||
}
|
||||
|
|
|
@ -17,4 +17,15 @@ public enum Comparators {
|
|||
return asc ? comparator : comparator.reversed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a nulls comparator.
|
||||
*
|
||||
* @param isAscending is ascending
|
||||
* @return if ascending, return nulls high, else return nulls low
|
||||
*/
|
||||
public static Comparator<Object> nullsComparator(boolean isAscending) {
|
||||
return isAscending
|
||||
? org.springframework.util.comparator.Comparators.nullsHigh()
|
||||
: org.springframework.util.comparator.Comparators.nullsLow();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ import java.util.stream.Stream;
|
|||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.util.comparator.Comparators;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.endpoint.SortResolver;
|
||||
import run.halo.app.extension.Comparators;
|
||||
import run.halo.app.extension.Extension;
|
||||
import run.halo.app.extension.router.IListRequest;
|
||||
|
||||
|
@ -66,9 +66,8 @@ public class SortableRequest extends IListRequest.QueryListRequest {
|
|||
BeanWrapper beanWrapper = new BeanWrapperImpl(extension);
|
||||
return beanWrapper.getPropertyValue(property);
|
||||
};
|
||||
Comparator<Object> nullsComparator =
|
||||
direction.isAscending() ? Comparators.nullsLow() : Comparators.nullsHigh();
|
||||
Comparator<T> comparator = Comparator.comparing(function, nullsComparator);
|
||||
Comparator<T> comparator = Comparator.comparing(function,
|
||||
Comparators.nullsComparator(direction.isAscending()));
|
||||
if (direction.isDescending()) {
|
||||
comparator = comparator.reversed();
|
||||
}
|
||||
|
|
|
@ -1,78 +1,72 @@
|
|||
package run.halo.app.content.impl;
|
||||
|
||||
package run.halo.app.content;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import run.halo.app.content.PostQuery;
|
||||
import run.halo.app.content.TestPost;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.content.Post;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
|
||||
/**
|
||||
* Tests for {@link PostServiceImpl}.
|
||||
* Tests for {@link PostQuery}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PostServiceImplTest {
|
||||
@Mock
|
||||
private ReactiveExtensionClient client;
|
||||
|
||||
@InjectMocks
|
||||
private PostServiceImpl postService;
|
||||
class PostQueryTest {
|
||||
|
||||
@Test
|
||||
void listPredicate() {
|
||||
void toPredicate() {
|
||||
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
|
||||
multiValueMap.put("category", List.of("category1", "category2"));
|
||||
PostQuery postQuery = new PostQuery(multiValueMap);
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.queryParams(multiValueMap)
|
||||
.exchange(mock(ServerWebExchange.class))
|
||||
.build();
|
||||
PostQuery postQuery = new PostQuery(request);
|
||||
|
||||
Post post = TestPost.postV1();
|
||||
post.getSpec().setTags(null);
|
||||
post.getStatusOrDefault().setContributors(null);
|
||||
post.getSpec().setCategories(List.of("category1"));
|
||||
boolean test = postService.postListPredicate(postQuery).test(post);
|
||||
boolean test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isTrue();
|
||||
|
||||
post.getSpec().setTags(List.of("tag1"));
|
||||
test = postService.postListPredicate(postQuery).test(post);
|
||||
test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isTrue();
|
||||
|
||||
// Do not include tags
|
||||
multiValueMap.put("tag", List.of("tag2"));
|
||||
post.getSpec().setTags(List.of("tag1"));
|
||||
post.getSpec().setCategories(null);
|
||||
test = postService.postListPredicate(postQuery).test(post);
|
||||
test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isFalse();
|
||||
|
||||
multiValueMap.put("tag", List.of());
|
||||
multiValueMap.remove("category");
|
||||
postQuery = new PostQuery(multiValueMap);
|
||||
request = MockServerRequest.builder()
|
||||
.exchange(mock(ServerWebExchange.class))
|
||||
.queryParams(multiValueMap).build();
|
||||
postQuery = new PostQuery(request);
|
||||
post.getSpec().setTags(List.of());
|
||||
test = postService.postListPredicate(postQuery).test(post);
|
||||
test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isTrue();
|
||||
|
||||
multiValueMap.put("labelSelector", List.of("hello"));
|
||||
test = postService.postListPredicate(postQuery).test(post);
|
||||
test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isFalse();
|
||||
|
||||
post.getMetadata().setLabels(Map.of("hello", "world"));
|
||||
test = postService.postListPredicate(postQuery).test(post);
|
||||
test = postQuery.toPredicate().test(post);
|
||||
assertThat(test).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void draftPost() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,25 @@
|
|||
package run.halo.app.content.comment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import lombok.NonNull;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import run.halo.app.core.extension.content.Comment;
|
||||
import run.halo.app.extension.Metadata;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommentQuery}.
|
||||
|
@ -12,13 +27,14 @@ import org.springframework.util.MultiValueMap;
|
|||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CommentQueryTest {
|
||||
|
||||
@Test
|
||||
void getKeyword() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("keyword", "test");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getKeyword()).isEqualTo("test");
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -35,7 +51,7 @@ class CommentQueryTest {
|
|||
void getApproved() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("approved", "true");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getApproved()).isTrue();
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -48,11 +64,24 @@ class CommentQueryTest {
|
|||
queryParams.clear();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private CommentQuery getCommentQuery(MultiValueMap<String, String> queryParams) {
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.queryParams(queryParams)
|
||||
.exchange(exchange)
|
||||
.build();
|
||||
ServerHttpRequest httpRequest = mock(ServerHttpRequest.class);
|
||||
lenient().when(exchange.getRequest()).thenReturn(httpRequest);
|
||||
lenient().when(httpRequest.getQueryParams()).thenReturn(queryParams);
|
||||
return new CommentQuery(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHidden() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("hidden", "true");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getHidden()).isTrue();
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -69,7 +98,7 @@ class CommentQueryTest {
|
|||
void getAllowNotification() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("allowNotification", "true");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getAllowNotification()).isTrue();
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -86,7 +115,7 @@ class CommentQueryTest {
|
|||
void getTop() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("top", "true");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getTop()).isTrue();
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -103,7 +132,7 @@ class CommentQueryTest {
|
|||
void getOwnerKind() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("ownerKind", "test-owner-kind");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getOwnerKind()).isEqualTo("test-owner-kind");
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -120,7 +149,7 @@ class CommentQueryTest {
|
|||
void getOwnerName() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("ownerName", "test-owner-name");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getOwnerName()).isEqualTo("test-owner-name");
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -137,7 +166,7 @@ class CommentQueryTest {
|
|||
void getSubjectKind() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("subjectKind", "test-subject-kind");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getSubjectKind()).isEqualTo("test-subject-kind");
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -154,7 +183,7 @@ class CommentQueryTest {
|
|||
void getSubjectName() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("subjectName", "test-subject-name");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
assertThat(commentQuery.getSubjectName()).isEqualTo("test-subject-name");
|
||||
queryParams.clear();
|
||||
|
||||
|
@ -167,37 +196,166 @@ class CommentQueryTest {
|
|||
queryParams.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSort() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", CommentSorter.REPLY_COUNT.name());
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
assertThat(commentQuery.getSort()).isEqualTo(CommentSorter.REPLY_COUNT);
|
||||
queryParams.clear();
|
||||
@Nested
|
||||
class CommentSortTest {
|
||||
@Test
|
||||
void sortByCreateTimeAsc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.set("sort", "creationTimestamp,asc");
|
||||
CommentQuery commentQuery = getCommentQuery(queryParams);
|
||||
Comparator<Comment> createTimeSorter = commentQuery.toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "C", "A"));
|
||||
}
|
||||
|
||||
queryParams.add("sort", "");
|
||||
assertThat(commentQuery.getSort()).isNull();
|
||||
queryParams.clear();
|
||||
@Test
|
||||
void sortByCreateTimeDesc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", "creationTimestamp,desc");
|
||||
Comparator<Comment> createTimeSorter = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("A", "B", "C"));
|
||||
}
|
||||
|
||||
queryParams.add("sort", "nothing");
|
||||
assertThat(commentQuery.getSort()).isNull();
|
||||
queryParams.clear();
|
||||
}
|
||||
@Test
|
||||
void sortByReplyCountAsc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", "replyCount,asc");
|
||||
Comparator<Comment> comparator = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("A", "B", "C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSortOrder() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sortOrder", "true");
|
||||
CommentQuery commentQuery = new CommentQuery(queryParams);
|
||||
assertThat(commentQuery.getSortOrder()).isTrue();
|
||||
queryParams.clear();
|
||||
@Test
|
||||
void sortByReplyCountDesc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", "replyCount,desc");
|
||||
Comparator<Comment> comparator = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("C", "B", "A"));
|
||||
}
|
||||
|
||||
queryParams.add("sortOrder", "");
|
||||
assertThat(commentQuery.getSortOrder()).isNull();
|
||||
queryParams.clear();
|
||||
@Test
|
||||
void sortByLastReplyTimeAsc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", "lastReplyTime,asc");
|
||||
Comparator<Comment> comparator = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("C", "A", "B"));
|
||||
}
|
||||
|
||||
queryParams.add("sortOrder", null);
|
||||
assertThat(commentQuery.getSortOrder()).isNull();
|
||||
queryParams.clear();
|
||||
@Test
|
||||
void sortByLastReplyTimeDesc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
queryParams.add("sort", "lastReplyTime,desc");
|
||||
Comparator<Comment> comparator = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "A", "C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByDefaultDesc() {
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
Comparator<Comment> comparator = getCommentQuery(queryParams).toComparator();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "A", "C"));
|
||||
|
||||
List<String> commentList = commentsIncludeNoReply().stream()
|
||||
.sorted(comparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentList).isEqualTo(List.of("D", "E", "B", "A", "C"));
|
||||
}
|
||||
|
||||
List<Comment> comments() {
|
||||
final Instant now = Instant.now();
|
||||
Comment commentA = new Comment();
|
||||
commentA.setMetadata(new Metadata());
|
||||
commentA.getMetadata().setName("A");
|
||||
// create time
|
||||
commentA.getMetadata().setCreationTimestamp(now.plusSeconds(10));
|
||||
commentA.setSpec(new Comment.CommentSpec());
|
||||
commentA.getSpec().setCreationTime(commentA.getMetadata().getCreationTimestamp());
|
||||
|
||||
commentA.setStatus(new Comment.CommentStatus());
|
||||
// last reply time
|
||||
commentA.getStatus().setLastReplyTime(now.plusSeconds(5));
|
||||
// reply count
|
||||
commentA.getStatus().setReplyCount(3);
|
||||
|
||||
Comment commentB = new Comment();
|
||||
commentB.setMetadata(new Metadata());
|
||||
commentB.getMetadata().setName("B");
|
||||
commentB.getMetadata().setCreationTimestamp(now.plusSeconds(5));
|
||||
commentB.setSpec(new Comment.CommentSpec());
|
||||
commentB.setStatus(new Comment.CommentStatus());
|
||||
commentB.getStatus().setLastReplyTime(now.plusSeconds(15));
|
||||
commentB.getStatus().setReplyCount(8);
|
||||
commentB.getSpec().setCreationTime(commentB.getMetadata().getCreationTimestamp());
|
||||
|
||||
Comment commentC = new Comment();
|
||||
commentC.setMetadata(new Metadata());
|
||||
commentC.getMetadata().setName("C");
|
||||
|
||||
commentC.getMetadata().setCreationTimestamp(now.plusSeconds(5));
|
||||
|
||||
commentC.setSpec(new Comment.CommentSpec());
|
||||
commentC.setStatus(new Comment.CommentStatus());
|
||||
commentC.getStatus().setLastReplyTime(now.plusSeconds(3));
|
||||
commentC.getStatus().setReplyCount(10);
|
||||
commentC.getSpec().setCreationTime(commentC.getMetadata().getCreationTimestamp());
|
||||
|
||||
return List.of(commentA, commentB, commentC);
|
||||
}
|
||||
|
||||
List<Comment> commentsIncludeNoReply() {
|
||||
|
||||
final Instant now = Instant.now();
|
||||
Comment commentD = new Comment();
|
||||
commentD.setMetadata(new Metadata());
|
||||
commentD.getMetadata().setName("D");
|
||||
|
||||
commentD.getMetadata().setCreationTimestamp(now.plusSeconds(50));
|
||||
|
||||
commentD.setSpec(new Comment.CommentSpec());
|
||||
commentD.getSpec().setCreationTime(commentD.getMetadata().getCreationTimestamp());
|
||||
commentD.setStatus(new Comment.CommentStatus());
|
||||
|
||||
Comment commentE = new Comment();
|
||||
commentE.setMetadata(new Metadata());
|
||||
commentE.getMetadata().setName("E");
|
||||
|
||||
commentE.getMetadata().setCreationTimestamp(now.plusSeconds(20));
|
||||
commentE.setSpec(new Comment.CommentSpec());
|
||||
commentE.getSpec().setCreationTime(commentE.getMetadata().getCreationTimestamp());
|
||||
commentE.setStatus(new Comment.CommentStatus());
|
||||
|
||||
List<Comment> comments = new ArrayList<>(comments());
|
||||
comments.add(commentD);
|
||||
comments.add(commentE);
|
||||
|
||||
return comments;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import static org.mockito.ArgumentMatchers.any;
|
|||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
@ -21,10 +22,13 @@ import org.mockito.InjectMocks;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import run.halo.app.content.TestPost;
|
||||
|
@ -115,8 +119,17 @@ class CommentServiceImplTest {
|
|||
when(userService.getUserOrGhost("B-owner"))
|
||||
.thenReturn(Mono.just(createUser("B-owner")));
|
||||
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.queryParams(queryParams)
|
||||
.exchange(exchange)
|
||||
.build();
|
||||
ServerHttpRequest httpRequest = mock(ServerHttpRequest.class);
|
||||
when(exchange.getRequest()).thenReturn(httpRequest);
|
||||
when(httpRequest.getQueryParams()).thenReturn(queryParams);
|
||||
Mono<ListResult<ListedComment>> listResultMono =
|
||||
commentService.listComment(new CommentQuery(new LinkedMultiValueMap<>()));
|
||||
commentService.listComment(new CommentQuery(request));
|
||||
Counter counterA = new Counter();
|
||||
counterA.setUpvote(3);
|
||||
String commentACounter = MeterUtils.nameOf(Comment.class, "A");
|
||||
|
@ -214,8 +227,11 @@ class CommentServiceImplTest {
|
|||
queryParams.add("subjectKind", "Post");
|
||||
queryParams.add("subjectName", "fake-post");
|
||||
|
||||
final Predicate<Comment> predicate =
|
||||
commentService.commentPredicate(new CommentQuery(queryParams));
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.queryParams(queryParams)
|
||||
.exchange(mock(ServerWebExchange.class))
|
||||
.build();
|
||||
final Predicate<Comment> predicate = new CommentQuery(request).toPredicate();
|
||||
|
||||
Comment comment = comment("A");
|
||||
comment.getSpec().setRaw("hello-world");
|
||||
|
@ -233,8 +249,11 @@ class CommentServiceImplTest {
|
|||
|
||||
queryParams.remove("keyword");
|
||||
queryParams.add("keyword", "nothing");
|
||||
final Predicate<Comment> predicateTwo =
|
||||
commentService.commentPredicate(new CommentQuery(queryParams));
|
||||
request = MockServerRequest.builder()
|
||||
.queryParams(queryParams)
|
||||
.exchange(mock(ServerWebExchange.class))
|
||||
.build();
|
||||
final Predicate<Comment> predicateTwo = new CommentQuery(request).toPredicate();
|
||||
assertThat(predicateTwo.test(comment)).isFalse();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
package run.halo.app.content.comment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import run.halo.app.core.extension.content.Comment;
|
||||
import run.halo.app.extension.Metadata;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommentSorter}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class CommentSorterTest {
|
||||
|
||||
@Test
|
||||
void sortByCreateTimeAsc() {
|
||||
Comparator<Comment> createTimeSorter = CommentSorter.from(CommentSorter.CREATE_TIME);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "C", "A"));
|
||||
|
||||
createTimeSorter = CommentSorter.from(CommentSorter.CREATE_TIME, true);
|
||||
commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "C", "A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByCreateTimeDesc() {
|
||||
Comparator<Comment> createTimeSorter = CommentSorter.from(CommentSorter.CREATE_TIME, false);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("A", "C", "B"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByReplyCountAsc() {
|
||||
Comparator<Comment> createTimeSorter = CommentSorter.from(CommentSorter.REPLY_COUNT);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("A", "B", "C"));
|
||||
|
||||
createTimeSorter = CommentSorter.from(CommentSorter.REPLY_COUNT, true);
|
||||
commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("A", "B", "C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByReplyCountDesc() {
|
||||
Comparator<Comment> createTimeSorter = CommentSorter.from(CommentSorter.REPLY_COUNT, false);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("C", "B", "A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByLastReplyTimeAsc() {
|
||||
Comparator<Comment> createTimeSorter = CommentSorter.from(CommentSorter.LAST_REPLY_TIME);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("C", "A", "B"));
|
||||
|
||||
createTimeSorter = CommentSorter.from(CommentSorter.LAST_REPLY_TIME, true);
|
||||
commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("C", "A", "B"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByLastReplyTimeDesc() {
|
||||
Comparator<Comment> createTimeSorter =
|
||||
CommentSorter.from(CommentSorter.LAST_REPLY_TIME, false);
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(createTimeSorter)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "A", "C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sortByDefaultDesc() {
|
||||
Comparator<Comment> defaultComparator = CommentSorter.lastReplyTimeComparator().reversed();
|
||||
List<String> commentNames = comments().stream()
|
||||
.sorted(defaultComparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentNames).isEqualTo(List.of("B", "A", "C"));
|
||||
|
||||
|
||||
List<String> commentList = commentsIncludeNoReply().stream()
|
||||
.sorted(defaultComparator)
|
||||
.map(comment -> comment.getMetadata().getName())
|
||||
.toList();
|
||||
assertThat(commentList).isEqualTo(List.of("D", "E", "B", "A", "C"));
|
||||
}
|
||||
|
||||
List<Comment> comments() {
|
||||
final Instant now = Instant.now();
|
||||
Comment commentA = new Comment();
|
||||
commentA.setMetadata(new Metadata());
|
||||
commentA.getMetadata().setName("A");
|
||||
// create time
|
||||
commentA.getMetadata().setCreationTimestamp(now.plusSeconds(10));
|
||||
commentA.setSpec(new Comment.CommentSpec());
|
||||
commentA.getSpec().setCreationTime(commentA.getMetadata().getCreationTimestamp());
|
||||
|
||||
commentA.setStatus(new Comment.CommentStatus());
|
||||
// last reply time
|
||||
commentA.getStatus().setLastReplyTime(now.plusSeconds(5));
|
||||
// reply count
|
||||
commentA.getStatus().setReplyCount(3);
|
||||
|
||||
Comment commentB = new Comment();
|
||||
commentB.setMetadata(new Metadata());
|
||||
commentB.getMetadata().setName("B");
|
||||
commentB.getMetadata().setCreationTimestamp(now.plusSeconds(5));
|
||||
commentB.setSpec(new Comment.CommentSpec());
|
||||
commentB.setStatus(new Comment.CommentStatus());
|
||||
commentB.getStatus().setLastReplyTime(now.plusSeconds(15));
|
||||
commentB.getStatus().setReplyCount(8);
|
||||
commentB.getSpec().setCreationTime(commentB.getMetadata().getCreationTimestamp());
|
||||
|
||||
Comment commentC = new Comment();
|
||||
commentC.setMetadata(new Metadata());
|
||||
commentC.getMetadata().setName("C");
|
||||
|
||||
commentC.getMetadata().setCreationTimestamp(now.plusSeconds(5));
|
||||
|
||||
commentC.setSpec(new Comment.CommentSpec());
|
||||
commentC.setStatus(new Comment.CommentStatus());
|
||||
commentC.getStatus().setLastReplyTime(now.plusSeconds(3));
|
||||
commentC.getStatus().setReplyCount(10);
|
||||
commentC.getSpec().setCreationTime(commentC.getMetadata().getCreationTimestamp());
|
||||
|
||||
return List.of(commentA, commentB, commentC);
|
||||
}
|
||||
|
||||
List<Comment> commentsIncludeNoReply() {
|
||||
|
||||
final Instant now = Instant.now();
|
||||
Comment commentD = new Comment();
|
||||
commentD.setMetadata(new Metadata());
|
||||
commentD.getMetadata().setName("D");
|
||||
|
||||
commentD.getMetadata().setCreationTimestamp(now.plusSeconds(50));
|
||||
|
||||
commentD.setSpec(new Comment.CommentSpec());
|
||||
commentD.getSpec().setCreationTime(commentD.getMetadata().getCreationTimestamp());
|
||||
commentD.setStatus(new Comment.CommentStatus());
|
||||
|
||||
Comment commentE = new Comment();
|
||||
commentE.setMetadata(new Metadata());
|
||||
commentE.getMetadata().setName("E");
|
||||
|
||||
commentE.getMetadata().setCreationTimestamp(now.plusSeconds(20));
|
||||
commentE.setSpec(new Comment.CommentSpec());
|
||||
commentE.getSpec().setCreationTime(commentE.getMetadata().getCreationTimestamp());
|
||||
commentE.setStatus(new Comment.CommentStatus());
|
||||
|
||||
List<Comment> comments = new ArrayList<>(comments());
|
||||
comments.add(commentD);
|
||||
comments.add(commentE);
|
||||
|
||||
return comments;
|
||||
|
||||
}
|
||||
}
|
|
@ -189,8 +189,7 @@ export const ApiConsoleHaloRunV1alpha1CommentApiAxiosParamCreator = function (
|
|||
* @param {string} [ownerName] Commenter name.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'LAST_REPLY_TIME' | 'REPLY_COUNT' | 'CREATE_TIME'} [sort] Comment collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,replyCount,lastReplyTime
|
||||
* @param {string} [subjectKind] Comment subject kind.
|
||||
* @param {string} [subjectName] Comment subject name.
|
||||
* @param {boolean} [top] Comment top display.
|
||||
|
@ -208,8 +207,7 @@ export const ApiConsoleHaloRunV1alpha1CommentApiAxiosParamCreator = function (
|
|||
ownerName?: string,
|
||||
page?: number,
|
||||
size?: number,
|
||||
sort?: "LAST_REPLY_TIME" | "REPLY_COUNT" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
subjectKind?: string,
|
||||
subjectName?: string,
|
||||
top?: boolean,
|
||||
|
@ -279,12 +277,8 @@ export const ApiConsoleHaloRunV1alpha1CommentApiAxiosParamCreator = function (
|
|||
localVarQueryParameter["size"] = size;
|
||||
}
|
||||
|
||||
if (sort !== undefined) {
|
||||
localVarQueryParameter["sort"] = sort;
|
||||
}
|
||||
|
||||
if (sortOrder !== undefined) {
|
||||
localVarQueryParameter["sortOrder"] = sortOrder;
|
||||
if (sort) {
|
||||
localVarQueryParameter["sort"] = Array.from(sort);
|
||||
}
|
||||
|
||||
if (subjectKind !== undefined) {
|
||||
|
@ -387,8 +381,7 @@ export const ApiConsoleHaloRunV1alpha1CommentApiFp = function (
|
|||
* @param {string} [ownerName] Commenter name.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'LAST_REPLY_TIME' | 'REPLY_COUNT' | 'CREATE_TIME'} [sort] Comment collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,replyCount,lastReplyTime
|
||||
* @param {string} [subjectKind] Comment subject kind.
|
||||
* @param {string} [subjectName] Comment subject name.
|
||||
* @param {boolean} [top] Comment top display.
|
||||
|
@ -406,8 +399,7 @@ export const ApiConsoleHaloRunV1alpha1CommentApiFp = function (
|
|||
ownerName?: string,
|
||||
page?: number,
|
||||
size?: number,
|
||||
sort?: "LAST_REPLY_TIME" | "REPLY_COUNT" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
subjectKind?: string,
|
||||
subjectName?: string,
|
||||
top?: boolean,
|
||||
|
@ -430,7 +422,6 @@ export const ApiConsoleHaloRunV1alpha1CommentApiFp = function (
|
|||
page,
|
||||
size,
|
||||
sort,
|
||||
sortOrder,
|
||||
subjectKind,
|
||||
subjectName,
|
||||
top,
|
||||
|
@ -512,7 +503,6 @@ export const ApiConsoleHaloRunV1alpha1CommentApiFactory = function (
|
|||
requestParameters.page,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.subjectKind,
|
||||
requestParameters.subjectName,
|
||||
requestParameters.top,
|
||||
|
@ -635,18 +625,11 @@ export interface ApiConsoleHaloRunV1alpha1CommentApiListCommentsRequest {
|
|||
readonly size?: number;
|
||||
|
||||
/**
|
||||
* Comment collation.
|
||||
* @type {'LAST_REPLY_TIME' | 'REPLY_COUNT' | 'CREATE_TIME'}
|
||||
* Sort property and direction of the list result. Supported fields: creationTimestamp,replyCount,lastReplyTime
|
||||
* @type {Array<string>}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1CommentApiListComments
|
||||
*/
|
||||
readonly sort?: "LAST_REPLY_TIME" | "REPLY_COUNT" | "CREATE_TIME";
|
||||
|
||||
/**
|
||||
* ascending order If it is true; otherwise, it is in descending order.
|
||||
* @type {boolean}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1CommentApiListComments
|
||||
*/
|
||||
readonly sortOrder?: boolean;
|
||||
readonly sort?: Array<string>;
|
||||
|
||||
/**
|
||||
* Comment subject kind.
|
||||
|
@ -737,7 +720,6 @@ export class ApiConsoleHaloRunV1alpha1CommentApi extends BaseAPI {
|
|||
requestParameters.page,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.subjectKind,
|
||||
requestParameters.subjectName,
|
||||
requestParameters.top,
|
||||
|
|
|
@ -230,8 +230,7 @@ export const ApiConsoleHaloRunV1alpha1PostApiAxiosParamCreator = function (
|
|||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {'DRAFT' | 'PENDING_APPROVAL' | 'PUBLISHED' | 'FAILED'} [publishPhase]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'PUBLISH_TIME' | 'CREATE_TIME'} [sort] Post collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @param {Array<string>} [tag]
|
||||
* @param {'PUBLIC' | 'INTERNAL' | 'PRIVATE'} [visible]
|
||||
* @param {*} [options] Override http request option.
|
||||
|
@ -246,8 +245,7 @@ export const ApiConsoleHaloRunV1alpha1PostApiAxiosParamCreator = function (
|
|||
page?: number,
|
||||
publishPhase?: "DRAFT" | "PENDING_APPROVAL" | "PUBLISHED" | "FAILED",
|
||||
size?: number,
|
||||
sort?: "PUBLISH_TIME" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
tag?: Array<string>,
|
||||
visible?: "PUBLIC" | "INTERNAL" | "PRIVATE",
|
||||
options: AxiosRequestConfig = {}
|
||||
|
@ -308,12 +306,8 @@ export const ApiConsoleHaloRunV1alpha1PostApiAxiosParamCreator = function (
|
|||
localVarQueryParameter["size"] = size;
|
||||
}
|
||||
|
||||
if (sort !== undefined) {
|
||||
localVarQueryParameter["sort"] = sort;
|
||||
}
|
||||
|
||||
if (sortOrder !== undefined) {
|
||||
localVarQueryParameter["sortOrder"] = sortOrder;
|
||||
if (sort) {
|
||||
localVarQueryParameter["sort"] = Array.from(sort);
|
||||
}
|
||||
|
||||
if (tag) {
|
||||
|
@ -724,8 +718,7 @@ export const ApiConsoleHaloRunV1alpha1PostApiFp = function (
|
|||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {'DRAFT' | 'PENDING_APPROVAL' | 'PUBLISHED' | 'FAILED'} [publishPhase]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'PUBLISH_TIME' | 'CREATE_TIME'} [sort] Post collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @param {Array<string>} [tag]
|
||||
* @param {'PUBLIC' | 'INTERNAL' | 'PRIVATE'} [visible]
|
||||
* @param {*} [options] Override http request option.
|
||||
|
@ -740,8 +733,7 @@ export const ApiConsoleHaloRunV1alpha1PostApiFp = function (
|
|||
page?: number,
|
||||
publishPhase?: "DRAFT" | "PENDING_APPROVAL" | "PUBLISHED" | "FAILED",
|
||||
size?: number,
|
||||
sort?: "PUBLISH_TIME" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
tag?: Array<string>,
|
||||
visible?: "PUBLIC" | "INTERNAL" | "PRIVATE",
|
||||
options?: AxiosRequestConfig
|
||||
|
@ -758,7 +750,6 @@ export const ApiConsoleHaloRunV1alpha1PostApiFp = function (
|
|||
publishPhase,
|
||||
size,
|
||||
sort,
|
||||
sortOrder,
|
||||
tag,
|
||||
visible,
|
||||
options
|
||||
|
@ -972,7 +963,6 @@ export const ApiConsoleHaloRunV1alpha1PostApiFactory = function (
|
|||
requestParameters.publishPhase,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.tag,
|
||||
requestParameters.visible,
|
||||
options
|
||||
|
@ -1169,18 +1159,11 @@ export interface ApiConsoleHaloRunV1alpha1PostApiListPostsRequest {
|
|||
readonly size?: number;
|
||||
|
||||
/**
|
||||
* Post collation.
|
||||
* @type {'PUBLISH_TIME' | 'CREATE_TIME'}
|
||||
* Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @type {Array<string>}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1PostApiListPosts
|
||||
*/
|
||||
readonly sort?: "PUBLISH_TIME" | "CREATE_TIME";
|
||||
|
||||
/**
|
||||
* ascending order If it is true; otherwise, it is in descending order.
|
||||
* @type {boolean}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1PostApiListPosts
|
||||
*/
|
||||
readonly sortOrder?: boolean;
|
||||
readonly sort?: Array<string>;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1365,7 +1348,6 @@ export class ApiConsoleHaloRunV1alpha1PostApi extends BaseAPI {
|
|||
requestParameters.publishPhase,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.tag,
|
||||
requestParameters.visible,
|
||||
options
|
||||
|
|
|
@ -234,8 +234,7 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiAxiosParamCreator =
|
|||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {'DRAFT' | 'PENDING_APPROVAL' | 'PUBLISHED' | 'FAILED'} [publishPhase]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'PUBLISH_TIME' | 'CREATE_TIME'} [sort] SinglePage collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @param {'PUBLIC' | 'INTERNAL' | 'PRIVATE'} [visible]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
|
@ -248,8 +247,7 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiAxiosParamCreator =
|
|||
page?: number,
|
||||
publishPhase?: "DRAFT" | "PENDING_APPROVAL" | "PUBLISHED" | "FAILED",
|
||||
size?: number,
|
||||
sort?: "PUBLISH_TIME" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
visible?: "PUBLIC" | "INTERNAL" | "PRIVATE",
|
||||
options: AxiosRequestConfig = {}
|
||||
): Promise<RequestArgs> => {
|
||||
|
@ -305,12 +303,8 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiAxiosParamCreator =
|
|||
localVarQueryParameter["size"] = size;
|
||||
}
|
||||
|
||||
if (sort !== undefined) {
|
||||
localVarQueryParameter["sort"] = sort;
|
||||
}
|
||||
|
||||
if (sortOrder !== undefined) {
|
||||
localVarQueryParameter["sortOrder"] = sortOrder;
|
||||
if (sort) {
|
||||
localVarQueryParameter["sort"] = Array.from(sort);
|
||||
}
|
||||
|
||||
if (visible !== undefined) {
|
||||
|
@ -612,8 +606,7 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiFp = function (
|
|||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {'DRAFT' | 'PENDING_APPROVAL' | 'PUBLISHED' | 'FAILED'} [publishPhase]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {'PUBLISH_TIME' | 'CREATE_TIME'} [sort] SinglePage collation.
|
||||
* @param {boolean} [sortOrder] ascending order If it is true; otherwise, it is in descending order.
|
||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @param {'PUBLIC' | 'INTERNAL' | 'PRIVATE'} [visible]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
|
@ -626,8 +619,7 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiFp = function (
|
|||
page?: number,
|
||||
publishPhase?: "DRAFT" | "PENDING_APPROVAL" | "PUBLISHED" | "FAILED",
|
||||
size?: number,
|
||||
sort?: "PUBLISH_TIME" | "CREATE_TIME",
|
||||
sortOrder?: boolean,
|
||||
sort?: Array<string>,
|
||||
visible?: "PUBLIC" | "INTERNAL" | "PRIVATE",
|
||||
options?: AxiosRequestConfig
|
||||
): Promise<
|
||||
|
@ -645,7 +637,6 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiFp = function (
|
|||
publishPhase,
|
||||
size,
|
||||
sort,
|
||||
sortOrder,
|
||||
visible,
|
||||
options
|
||||
);
|
||||
|
@ -807,7 +798,6 @@ export const ApiConsoleHaloRunV1alpha1SinglePageApiFactory = function (
|
|||
requestParameters.publishPhase,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.visible,
|
||||
options
|
||||
)
|
||||
|
@ -964,18 +954,11 @@ export interface ApiConsoleHaloRunV1alpha1SinglePageApiListSinglePagesRequest {
|
|||
readonly size?: number;
|
||||
|
||||
/**
|
||||
* SinglePage collation.
|
||||
* @type {'PUBLISH_TIME' | 'CREATE_TIME'}
|
||||
* Sort property and direction of the list result. Supported fields: creationTimestamp,publishTime
|
||||
* @type {Array<string>}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1SinglePageApiListSinglePages
|
||||
*/
|
||||
readonly sort?: "PUBLISH_TIME" | "CREATE_TIME";
|
||||
|
||||
/**
|
||||
* ascending order If it is true; otherwise, it is in descending order.
|
||||
* @type {boolean}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1SinglePageApiListSinglePages
|
||||
*/
|
||||
readonly sortOrder?: boolean;
|
||||
readonly sort?: Array<string>;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1117,7 +1100,6 @@ export class ApiConsoleHaloRunV1alpha1SinglePageApi extends BaseAPI {
|
|||
requestParameters.publishPhase,
|
||||
requestParameters.size,
|
||||
requestParameters.sort,
|
||||
requestParameters.sortOrder,
|
||||
requestParameters.visible,
|
||||
options
|
||||
)
|
||||
|
|
|
@ -427,10 +427,12 @@ core:
|
|||
result: "Owner: {owner}"
|
||||
sort:
|
||||
items:
|
||||
default: Default
|
||||
last_reply_time: Last reply time
|
||||
reply_count: Reply count
|
||||
creation_time: Creation time
|
||||
last_reply_time_desc: Recent reply
|
||||
last_reply_time_asc: Earlier reply
|
||||
reply_count_desc: More replies
|
||||
reply_count_asc: Fewer replies
|
||||
create_time_desc: Latest Created
|
||||
create_time_asc: Earliest Created
|
||||
list:
|
||||
fields:
|
||||
reply_count: "{count} Replies"
|
||||
|
|
|
@ -427,10 +427,12 @@ core:
|
|||
result: "评论者:{owner}"
|
||||
sort:
|
||||
items:
|
||||
default: 默认
|
||||
last_reply_time: 最后回复时间
|
||||
reply_count: 回复数
|
||||
creation_time: 创建时间
|
||||
last_reply_time_desc: 较近回复
|
||||
last_reply_time_asc: 较早回复
|
||||
reply_count_desc: 较多回复数
|
||||
reply_count_asc: 较少回复数
|
||||
create_time_desc: 较近创建
|
||||
create_time_asc: 较早创建
|
||||
list:
|
||||
fields:
|
||||
reply_count: "{count} 条回复"
|
||||
|
|
|
@ -427,10 +427,12 @@ core:
|
|||
result: "留言者:{owner}"
|
||||
sort:
|
||||
items:
|
||||
default: 預設
|
||||
last_reply_time: 最後回覆時間
|
||||
reply_count: 回覆數
|
||||
creation_time: 創建時間
|
||||
last_reply_time_desc: 較近回覆
|
||||
last_reply_time_asc: 較早回覆
|
||||
reply_count_desc: 較多回覆數
|
||||
reply_count_asc: 較少回覆數
|
||||
create_time_desc: 較近創建
|
||||
create_time_asc: 較早創建
|
||||
list:
|
||||
fields:
|
||||
reply_count: "{count} 條回覆"
|
||||
|
|
|
@ -34,6 +34,12 @@ const selectedCommentNames = ref<string[]>([]);
|
|||
const keyword = ref("");
|
||||
|
||||
// Filters
|
||||
|
||||
interface SortItem {
|
||||
label: string;
|
||||
sort: string;
|
||||
}
|
||||
|
||||
const ApprovedFilterItems: { label: string; value?: boolean }[] = [
|
||||
{
|
||||
label: t("core.comment.filters.status.items.all"),
|
||||
|
@ -49,27 +55,30 @@ const ApprovedFilterItems: { label: string; value?: boolean }[] = [
|
|||
},
|
||||
];
|
||||
|
||||
type Sort = "LAST_REPLY_TIME" | "REPLY_COUNT" | "CREATE_TIME";
|
||||
|
||||
const SortFilterItems: {
|
||||
label: string;
|
||||
value?: Sort;
|
||||
}[] = [
|
||||
const SortItems: SortItem[] = [
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.default"),
|
||||
value: undefined,
|
||||
label: t("core.comment.filters.sort.items.last_reply_time_desc"),
|
||||
sort: "lastReplyTime,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.last_reply_time"),
|
||||
value: "LAST_REPLY_TIME",
|
||||
label: t("core.comment.filters.sort.items.last_reply_time_asc"),
|
||||
sort: "lastReplyTime,asc",
|
||||
},
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.reply_count"),
|
||||
value: "REPLY_COUNT",
|
||||
label: t("core.comment.filters.sort.items.reply_count_desc"),
|
||||
sort: "replyCount,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.creation_time"),
|
||||
value: "CREATE_TIME",
|
||||
label: t("core.comment.filters.sort.items.reply_count_asc"),
|
||||
sort: "replyCount,asc",
|
||||
},
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.create_time_desc"),
|
||||
sort: "creationTimestamp,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.comment.filters.sort.items.create_time_asc"),
|
||||
sort: "creationTimestamp,asc",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -77,10 +86,7 @@ const selectedApprovedFilterItem = ref<{ label: string; value?: boolean }>(
|
|||
ApprovedFilterItems[0]
|
||||
);
|
||||
|
||||
const selectedSortFilterItem = ref<{
|
||||
label: string;
|
||||
value?: Sort;
|
||||
}>(SortFilterItems[0]);
|
||||
const selectedSortItem = ref<SortItem>();
|
||||
|
||||
const selectedUser = ref<User>();
|
||||
|
||||
|
@ -93,11 +99,8 @@ const handleApprovedFilterItemChange = (filterItem: {
|
|||
page.value = 1;
|
||||
};
|
||||
|
||||
const handleSortFilterItemChange = (filterItem: {
|
||||
label: string;
|
||||
value?: Sort;
|
||||
}) => {
|
||||
selectedSortFilterItem.value = filterItem;
|
||||
const handleSortItemChange = (sortItem: SortItem) => {
|
||||
selectedSortItem.value = sortItem;
|
||||
selectedCommentNames.value = [];
|
||||
page.value = 1;
|
||||
};
|
||||
|
@ -123,7 +126,7 @@ function handleClearKeyword() {
|
|||
const hasFilters = computed(() => {
|
||||
return (
|
||||
selectedApprovedFilterItem.value.value !== undefined ||
|
||||
selectedSortFilterItem.value.value !== undefined ||
|
||||
selectedSortItem.value ||
|
||||
selectedUser.value ||
|
||||
keyword.value
|
||||
);
|
||||
|
@ -131,7 +134,7 @@ const hasFilters = computed(() => {
|
|||
|
||||
function handleClearFilters() {
|
||||
selectedApprovedFilterItem.value = ApprovedFilterItems[0];
|
||||
selectedSortFilterItem.value = SortFilterItems[0];
|
||||
selectedSortItem.value = undefined;
|
||||
selectedUser.value = undefined;
|
||||
keyword.value = "";
|
||||
page.value = 1;
|
||||
|
@ -152,7 +155,7 @@ const {
|
|||
page,
|
||||
size,
|
||||
selectedApprovedFilterItem,
|
||||
selectedSortFilterItem,
|
||||
selectedSortItem,
|
||||
selectedUser,
|
||||
keyword,
|
||||
],
|
||||
|
@ -161,7 +164,7 @@ const {
|
|||
page: page.value,
|
||||
size: size.value,
|
||||
approved: selectedApprovedFilterItem.value.value,
|
||||
sort: selectedSortFilterItem.value.value,
|
||||
sort: [selectedSortItem.value?.sort].filter(Boolean) as string[],
|
||||
keyword: keyword.value,
|
||||
ownerName: selectedUser.value?.metadata.name,
|
||||
});
|
||||
|
@ -355,12 +358,12 @@ const handleApproveInBatch = async () => {
|
|||
</FilterTag>
|
||||
|
||||
<FilterTag
|
||||
v-if="selectedSortFilterItem.value != undefined"
|
||||
@close="handleSortFilterItemChange(SortFilterItems[0])"
|
||||
v-if="selectedSortItem"
|
||||
@close="handleSortItemChange(SortItems[0])"
|
||||
>
|
||||
{{
|
||||
$t("core.common.filters.results.sort", {
|
||||
sort: selectedSortFilterItem.label,
|
||||
sort: selectedSortItem.label,
|
||||
})
|
||||
}}
|
||||
</FilterTag>
|
||||
|
@ -437,12 +440,10 @@ const handleApproveInBatch = async () => {
|
|||
</div>
|
||||
<template #popper>
|
||||
<VDropdownItem
|
||||
v-for="(filterItem, index) in SortFilterItems"
|
||||
v-for="(filterItem, index) in SortItems"
|
||||
:key="index"
|
||||
:selected="
|
||||
selectedSortFilterItem.value === filterItem.value
|
||||
"
|
||||
@click="handleSortFilterItemChange(filterItem)"
|
||||
:selected="selectedSortItem?.sort === filterItem.sort"
|
||||
@click="handleSortItemChange(filterItem)"
|
||||
>
|
||||
{{ filterItem.label }}
|
||||
</VDropdownItem>
|
||||
|
|
|
@ -63,8 +63,7 @@ interface PublishStatusItem {
|
|||
|
||||
interface SortItem {
|
||||
label: string;
|
||||
sort: "PUBLISH_TIME" | "CREATE_TIME";
|
||||
sortOrder: boolean;
|
||||
sort: string;
|
||||
}
|
||||
|
||||
const VisibleItems: VisibleItem[] = [
|
||||
|
@ -100,23 +99,19 @@ const PublishStatusItems: PublishStatusItem[] = [
|
|||
const SortItems: SortItem[] = [
|
||||
{
|
||||
label: t("core.page.filters.sort.items.publish_time_desc"),
|
||||
sort: "PUBLISH_TIME",
|
||||
sortOrder: false,
|
||||
sort: "publishTime,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.page.filters.sort.items.publish_time_asc"),
|
||||
sort: "PUBLISH_TIME",
|
||||
sortOrder: true,
|
||||
sort: "publishTime,asc",
|
||||
},
|
||||
{
|
||||
label: t("core.page.filters.sort.items.create_time_desc"),
|
||||
sort: "CREATE_TIME",
|
||||
sortOrder: false,
|
||||
sort: "creationTimestamp,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.page.filters.sort.items.create_time_asc"),
|
||||
sort: "CREATE_TIME",
|
||||
sortOrder: true,
|
||||
sort: "creationTimestamp,asc",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -219,8 +214,7 @@ const {
|
|||
page: page.value,
|
||||
size: size.value,
|
||||
visible: selectedVisibleItem.value.value,
|
||||
sort: selectedSortItem.value?.sort,
|
||||
sortOrder: selectedSortItem.value?.sortOrder,
|
||||
sort: [selectedSortItem.value?.sort].filter(Boolean) as string[],
|
||||
keyword: keyword.value,
|
||||
contributor: contributors,
|
||||
});
|
||||
|
@ -652,10 +646,7 @@ const { mutate: changeVisibleMutation } = useMutation({
|
|||
<VDropdownItem
|
||||
v-for="(sortItem, index) in SortItems"
|
||||
:key="index"
|
||||
:selected="
|
||||
sortItem.sort === selectedSortItem?.sort &&
|
||||
sortItem.sortOrder === selectedSortItem?.sortOrder
|
||||
"
|
||||
:selected="sortItem.sort === selectedSortItem?.sort"
|
||||
@click="handleSortItemChange(sortItem)"
|
||||
>
|
||||
{{ sortItem.label }}
|
||||
|
|
|
@ -70,8 +70,7 @@ interface PublishStatusItem {
|
|||
|
||||
interface SortItem {
|
||||
label: string;
|
||||
sort: "PUBLISH_TIME" | "CREATE_TIME";
|
||||
sortOrder: boolean;
|
||||
sort: string;
|
||||
}
|
||||
|
||||
const VisibleItems: VisibleItem[] = [
|
||||
|
@ -107,23 +106,19 @@ const PublishStatusItems: PublishStatusItem[] = [
|
|||
const SortItems: SortItem[] = [
|
||||
{
|
||||
label: t("core.post.filters.sort.items.publish_time_desc"),
|
||||
sort: "PUBLISH_TIME",
|
||||
sortOrder: false,
|
||||
sort: "publishTime,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.post.filters.sort.items.publish_time_asc"),
|
||||
sort: "PUBLISH_TIME",
|
||||
sortOrder: true,
|
||||
sort: "publishTime,asc",
|
||||
},
|
||||
{
|
||||
label: t("core.post.filters.sort.items.create_time_desc"),
|
||||
sort: "CREATE_TIME",
|
||||
sortOrder: false,
|
||||
sort: "creationTimestamp,desc",
|
||||
},
|
||||
{
|
||||
label: t("core.post.filters.sort.items.create_time_asc"),
|
||||
sort: "CREATE_TIME",
|
||||
sortOrder: true,
|
||||
sort: "creationTimestamp,asc",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -254,8 +249,7 @@ const {
|
|||
page: page.value,
|
||||
size: size.value,
|
||||
visible: selectedVisibleItem.value?.value,
|
||||
sort: selectedSortItem.value?.sort,
|
||||
sortOrder: selectedSortItem.value?.sortOrder,
|
||||
sort: [selectedSortItem.value?.sort].filter(Boolean) as string[],
|
||||
keyword: keyword.value,
|
||||
category: categories,
|
||||
tag: tags,
|
||||
|
@ -715,10 +709,7 @@ const { mutate: changeVisibleMutation } = useMutation({
|
|||
<VDropdownItem
|
||||
v-for="(sortItem, index) in SortItems"
|
||||
:key="index"
|
||||
:selected="
|
||||
sortItem.sort === selectedSortItem?.sort &&
|
||||
sortItem.sortOrder === selectedSortItem?.sortOrder
|
||||
"
|
||||
:selected="sortItem.sort === selectedSortItem?.sort"
|
||||
@click="handleSortItemChange(sortItem)"
|
||||
>
|
||||
{{ sortItem.label }}
|
||||
|
|
|
@ -21,8 +21,7 @@ const { data } = useQuery<ListedPost[]>({
|
|||
`${postLabels.DELETED}=false`,
|
||||
`${postLabels.PUBLISHED}=true`,
|
||||
],
|
||||
sort: "PUBLISH_TIME",
|
||||
sortOrder: false,
|
||||
sort: ["publishTime,desc"],
|
||||
page: 1,
|
||||
size: 10,
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue