mirror of https://github.com/halo-dev/halo
refactor: optimize notification and subscription query using index (#5414)
### What type of PR is this? /kind improvement /area core /milestone 2.13.x ### What this PR does / why we need it: 使用索引机制优化通知和订阅查询以提高性能 how to test it 测试通知列表不报错即可 ### Does this PR introduce a user-facing change? ```release-note 使用索引机制优化通知和订阅查询以提高性能 ```pull/5422/head^2 v2.13.0-rc.1
parent
d2f569699b
commit
11114416fa
|
@ -0,0 +1,28 @@
|
||||||
|
package run.halo.app.core.extension.notification;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link Subscription}.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.13.0
|
||||||
|
*/
|
||||||
|
class SubscriptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void reasonSubjectToStringTest() {
|
||||||
|
Subscription.ReasonSubject subject = new Subscription.ReasonSubject();
|
||||||
|
subject.setApiVersion("v1");
|
||||||
|
subject.setKind("Kind");
|
||||||
|
subject.setName("Name");
|
||||||
|
|
||||||
|
String expected = "Kind#v1/Name";
|
||||||
|
String actual = subject.toString();
|
||||||
|
|
||||||
|
assertThat(actual).isEqualTo(expected);
|
||||||
|
}
|
||||||
|
}
|
|
@ -260,10 +260,58 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
|
||||||
// notification.halo.run
|
// notification.halo.run
|
||||||
schemeManager.register(ReasonType.class);
|
schemeManager.register(ReasonType.class);
|
||||||
schemeManager.register(Reason.class);
|
schemeManager.register(Reason.class);
|
||||||
schemeManager.register(NotificationTemplate.class);
|
schemeManager.register(NotificationTemplate.class, indexSpecs -> {
|
||||||
schemeManager.register(Subscription.class);
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.reasonSelector.reasonType")
|
||||||
|
.setIndexFunc(simpleAttribute(NotificationTemplate.class,
|
||||||
|
template -> template.getSpec().getReasonSelector().getReasonType()))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
schemeManager.register(Subscription.class, indexSpecs -> {
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.reason.reasonType")
|
||||||
|
.setIndexFunc(simpleAttribute(Subscription.class,
|
||||||
|
subscription -> subscription.getSpec().getReason().getReasonType()))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.reason.subject")
|
||||||
|
.setIndexFunc(simpleAttribute(Subscription.class,
|
||||||
|
subscription -> subscription.getSpec().getReason().getSubject().toString()))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.subscriber")
|
||||||
|
.setIndexFunc(simpleAttribute(Subscription.class,
|
||||||
|
subscription -> subscription.getSpec().getSubscriber().toString()))
|
||||||
|
);
|
||||||
|
});
|
||||||
schemeManager.register(NotifierDescriptor.class);
|
schemeManager.register(NotifierDescriptor.class);
|
||||||
schemeManager.register(Notification.class);
|
schemeManager.register(Notification.class, indexSpecs -> {
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.unread")
|
||||||
|
.setIndexFunc(simpleAttribute(Notification.class,
|
||||||
|
notification -> String.valueOf(notification.getSpec().isUnread())))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.reason")
|
||||||
|
.setIndexFunc(simpleAttribute(Notification.class,
|
||||||
|
notification -> notification.getSpec().getReason()))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.recipient")
|
||||||
|
.setIndexFunc(simpleAttribute(Notification.class,
|
||||||
|
notification -> notification.getSpec().getRecipient()))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.title")
|
||||||
|
.setIndexFunc(simpleAttribute(Notification.class,
|
||||||
|
notification -> notification.getSpec().getTitle()))
|
||||||
|
);
|
||||||
|
indexSpecs.add(new IndexSpec()
|
||||||
|
.setName("spec.rawContent")
|
||||||
|
.setIndexFunc(simpleAttribute(Notification.class,
|
||||||
|
notification -> notification.getSpec().getRawContent()))
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DefaultSchemeManager createSchemeManager(
|
private static DefaultSchemeManager createSchemeManager(
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package run.halo.app.notification;
|
package run.halo.app.notification;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.and;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.equal;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.or;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -12,7 +15,9 @@ import lombok.Builder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.scheduler.Schedulers;
|
import reactor.core.scheduler.Schedulers;
|
||||||
|
@ -23,8 +28,10 @@ import run.halo.app.core.extension.notification.Reason;
|
||||||
import run.halo.app.core.extension.notification.ReasonType;
|
import run.halo.app.core.extension.notification.ReasonType;
|
||||||
import run.halo.app.core.extension.notification.Subscription;
|
import run.halo.app.core.extension.notification.Subscription;
|
||||||
import run.halo.app.extension.GroupVersionKind;
|
import run.halo.app.extension.GroupVersionKind;
|
||||||
|
import run.halo.app.extension.ListOptions;
|
||||||
import run.halo.app.extension.Metadata;
|
import run.halo.app.extension.Metadata;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
import run.halo.app.extension.router.selector.FieldSelector;
|
||||||
import run.halo.app.notification.endpoint.SubscriptionRouter;
|
import run.halo.app.notification.endpoint.SubscriptionRouter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,9 +105,11 @@ public class DefaultNotificationCenter implements NotificationCenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
Flux<Subscription> listSubscription(Subscription.Subscriber subscriber) {
|
Flux<Subscription> listSubscription(Subscription.Subscriber subscriber) {
|
||||||
return client.list(Subscription.class,
|
var listOptions = new ListOptions();
|
||||||
subscription -> subscription.getSpec().getSubscriber().equals(subscriber),
|
listOptions.setFieldSelector(FieldSelector.of(
|
||||||
null);
|
equal("spec.subscriber", subscriber.toString()))
|
||||||
|
);
|
||||||
|
return client.listAll(Subscription.class, listOptions, defaultSort());
|
||||||
}
|
}
|
||||||
|
|
||||||
Flux<String> getNotifiersBySubscriber(Subscription.Subscriber subscriber, Reason reason) {
|
Flux<String> getNotifiersBySubscriber(Subscription.Subscriber subscriber, Reason reason) {
|
||||||
|
@ -310,31 +319,41 @@ public class DefaultNotificationCenter implements NotificationCenter {
|
||||||
|
|
||||||
Flux<Subscription> listObservers(String reasonTypeName,
|
Flux<Subscription> listObservers(String reasonTypeName,
|
||||||
Subscription.ReasonSubject reasonSubject) {
|
Subscription.ReasonSubject reasonSubject) {
|
||||||
var distinctKeyPredicate = subscriptionDistinctKeyPredicate();
|
Assert.notNull(reasonTypeName, "The reasonTypeName must not be null");
|
||||||
return client.list(Subscription.class,
|
Assert.notNull(reasonSubject, "The reasonSubject must not be null");
|
||||||
subscription -> {
|
final var listOptions = new ListOptions();
|
||||||
var interestReason = subscription.getSpec().getReason();
|
var matchAllSubject = new Subscription.ReasonSubject();
|
||||||
var sourceSubject = interestReason.getSubject();
|
matchAllSubject.setKind(reasonSubject.getKind());
|
||||||
if (StringUtils.isBlank(sourceSubject.getName())) {
|
matchAllSubject.setApiVersion(reasonSubject.getApiVersion());
|
||||||
return interestReason.getReasonType().equals(reasonTypeName)
|
var fieldQuery = and(equal("spec.reason.reasonType", reasonTypeName),
|
||||||
&& sourceSubject.getApiVersion().equals(reasonSubject.getApiVersion())
|
or(equal("spec.reason.subject", reasonSubject.toString()),
|
||||||
&& sourceSubject.getKind().equals(reasonSubject.getKind());
|
// source reason subject name is blank present match all
|
||||||
|
equal("spec.reason.subject", matchAllSubject.toString())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(fieldQuery));
|
||||||
|
return distinctByKey(client.listAll(Subscription.class, listOptions, defaultSort()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Flux<Subscription> distinctByKey(Flux<Subscription> source) {
|
||||||
|
final var distinctKeyPredicate = subscriptionDistinctKeyPredicate();
|
||||||
|
return source.distinct(Function.identity(), HashSet<Subscription>::new,
|
||||||
|
(set, val) -> {
|
||||||
|
for (Subscription subscription : set) {
|
||||||
|
if (distinctKeyPredicate.test(subscription, val)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return interestReason.getReasonType().equals(reasonTypeName)
|
}
|
||||||
&& interestReason.getSubject().equals(reasonSubject);
|
// no duplicated return true
|
||||||
}, null)
|
set.add(val);
|
||||||
.distinct(Function.identity(), HashSet<Subscription>::new,
|
return true;
|
||||||
(set, val) -> {
|
},
|
||||||
for (Subscription subscription : set) {
|
HashSet::clear);
|
||||||
if (distinctKeyPredicate.test(subscription, val)) {
|
}
|
||||||
return false;
|
|
||||||
}
|
Sort defaultSort() {
|
||||||
}
|
return Sort.by(Sort.Order.asc("metadata.creationTimestamp"),
|
||||||
// no duplicated return true
|
Sort.Order.asc("metadata.name"));
|
||||||
set.add(val);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
HashSet::clear);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BiPredicate<Subscription, Subscription> subscriptionDistinctKeyPredicate() {
|
static BiPredicate<Subscription, Subscription> subscriptionDistinctKeyPredicate() {
|
||||||
|
|
|
@ -26,10 +26,7 @@ public class DefaultNotificationService implements UserNotificationService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ListResult<Notification>> listByUser(String username, UserNotificationQuery query) {
|
public Mono<ListResult<Notification>> listByUser(String username, UserNotificationQuery query) {
|
||||||
var predicate = query.toPredicate()
|
return client.listBy(Notification.class, query.toListOptions(), query.toPageRequest());
|
||||||
.and(notification -> isRecipient(notification, username));
|
|
||||||
return client.list(Notification.class, predicate, query.toComparator(),
|
|
||||||
query.getPage(), query.getSize());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package run.halo.app.notification;
|
package run.halo.app.notification;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.equal;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -12,11 +13,14 @@ import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.notification.NotificationTemplate;
|
import run.halo.app.core.extension.notification.NotificationTemplate;
|
||||||
|
import run.halo.app.extension.ListOptions;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
import run.halo.app.extension.router.selector.FieldSelector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default implementation of {@link ReasonNotificationTemplateSelector}.
|
* A default implementation of {@link ReasonNotificationTemplateSelector}.
|
||||||
|
@ -32,7 +36,11 @@ public class ReasonNotificationTemplateSelectorImpl implements ReasonNotificatio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<NotificationTemplate> select(String reasonType, Locale locale) {
|
public Mono<NotificationTemplate> select(String reasonType, Locale locale) {
|
||||||
return client.list(NotificationTemplate.class, matchReasonType(reasonType), null)
|
var listOptions = new ListOptions();
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(
|
||||||
|
equal("spec.reasonSelector.reasonType", reasonType))
|
||||||
|
);
|
||||||
|
return client.listAll(NotificationTemplate.class, listOptions, Sort.unsorted())
|
||||||
.collect(Collectors.groupingBy(
|
.collect(Collectors.groupingBy(
|
||||||
getLanguageKey(),
|
getLanguageKey(),
|
||||||
Collectors.maxBy(Comparator.comparing(t -> t.getMetadata().getCreationTimestamp()))
|
Collectors.maxBy(Comparator.comparing(t -> t.getMetadata().getCreationTimestamp()))
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
package run.halo.app.notification;
|
package run.halo.app.notification;
|
||||||
|
|
||||||
import static java.util.Comparator.comparing;
|
import static run.halo.app.extension.index.query.QueryFactory.and;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.contains;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.equal;
|
||||||
|
import static run.halo.app.extension.index.query.QueryFactory.or;
|
||||||
|
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import run.halo.app.core.extension.endpoint.SortResolver;
|
import run.halo.app.core.extension.endpoint.SortResolver;
|
||||||
import run.halo.app.core.extension.notification.Notification;
|
import run.halo.app.extension.ListOptions;
|
||||||
import run.halo.app.extension.Comparators;
|
import run.halo.app.extension.PageRequest;
|
||||||
|
import run.halo.app.extension.PageRequestImpl;
|
||||||
import run.halo.app.extension.router.IListRequest;
|
import run.halo.app.extension.router.IListRequest;
|
||||||
|
import run.halo.app.extension.router.selector.FieldSelector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification query object for authenticated user.
|
* Notification query object for authenticated user.
|
||||||
|
@ -27,9 +29,12 @@ public class UserNotificationQuery extends IListRequest.QueryListRequest {
|
||||||
|
|
||||||
private final ServerWebExchange exchange;
|
private final ServerWebExchange exchange;
|
||||||
|
|
||||||
public UserNotificationQuery(ServerWebExchange exchange) {
|
private final String username;
|
||||||
|
|
||||||
|
public UserNotificationQuery(ServerWebExchange exchange, String username) {
|
||||||
super(exchange.getRequest().getQueryParams());
|
super(exchange.getRequest().getQueryParams());
|
||||||
this.exchange = exchange;
|
this.exchange = exchange;
|
||||||
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -37,79 +42,44 @@ public class UserNotificationQuery extends IListRequest.QueryListRequest {
|
||||||
return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null);
|
return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Schema(description = "true for unread, false for read, null for all")
|
|
||||||
public Boolean getUnRead() {
|
|
||||||
var unreadStr = queryParams.getFirst("unRead");
|
|
||||||
return StringUtils.isBlank(unreadStr) ? null : Boolean.parseBoolean(unreadStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Schema(description = "Filter by notification reason")
|
|
||||||
public String getReason() {
|
|
||||||
return StringUtils.defaultIfBlank(queryParams.getFirst("reason"), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ArraySchema(uniqueItems = true,
|
@ArraySchema(uniqueItems = true,
|
||||||
arraySchema = @Schema(name = "sort",
|
arraySchema = @Schema(name = "sort",
|
||||||
description = "Sort property and direction of the list result. Supported fields: "
|
description = "Sort property and direction of the list result. Supported fields: "
|
||||||
+ "creationTimestamp"),
|
+ "metadata.creationTimestamp"),
|
||||||
schema = @Schema(description = "like field,asc or field,desc",
|
schema = @Schema(description = "like field,asc or field,desc",
|
||||||
implementation = String.class,
|
implementation = String.class,
|
||||||
example = "creationTimestamp,desc"))
|
example = "creationTimestamp,desc"))
|
||||||
public Sort getSort() {
|
public Sort getSort() {
|
||||||
return SortResolver.defaultInstance.resolve(exchange);
|
var sort = SortResolver.defaultInstance.resolve(exchange);
|
||||||
|
return sort.and(Sort.by(
|
||||||
|
Sort.Order.desc("metadata.creationTimestamp"),
|
||||||
|
Sort.Order.desc("metadata.name"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a predicate from the query object.
|
* Build a list options from the query object.
|
||||||
*
|
|
||||||
* @return a predicate
|
|
||||||
*/
|
*/
|
||||||
public Predicate<Notification> toPredicate() {
|
public ListOptions toListOptions() {
|
||||||
var unRead = getUnRead();
|
var listOptions =
|
||||||
var reason = getReason();
|
labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector());
|
||||||
Predicate<Notification> predicate = notification -> true;
|
var filedQuery = listOptions.getFieldSelector().query();
|
||||||
if (unRead != null) {
|
if (StringUtils.isNotBlank(getKeyword())) {
|
||||||
predicate = predicate.and(notification
|
filedQuery = and(filedQuery,
|
||||||
-> notification.getSpec().isUnread() == unRead);
|
or(
|
||||||
|
contains("spec.title", getKeyword()),
|
||||||
|
contains("spec.rawContent", getKeyword())
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isNotBlank(username)) {
|
||||||
if (reason != null) {
|
filedQuery = and(filedQuery, equal("spec.recipient", username));
|
||||||
predicate = predicate.and(notification
|
|
||||||
-> reason.equals(notification.getSpec().getReason()));
|
|
||||||
}
|
}
|
||||||
|
listOptions.setFieldSelector(FieldSelector.of(filedQuery));
|
||||||
if (getKeyword() != null) {
|
return listOptions;
|
||||||
predicate = predicate.and(notification
|
|
||||||
-> notification.getSpec().getTitle().contains(getKeyword())
|
|
||||||
|| notification.getSpec().getHtmlContent().contains(getKeyword())
|
|
||||||
|| notification.getSpec().getRawContent().contains(getKeyword()));
|
|
||||||
}
|
|
||||||
return predicate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public PageRequest toPageRequest() {
|
||||||
* Build a comparator from the query object.
|
return PageRequestImpl.of(getPage(), getSize(), getSort());
|
||||||
*
|
|
||||||
* @return a comparator
|
|
||||||
*/
|
|
||||||
public Comparator<Notification> toComparator() {
|
|
||||||
var sort = getSort();
|
|
||||||
var creationTimestampOrder = sort.getOrderFor("creationTimestamp");
|
|
||||||
List<Comparator<Notification>> comparators = new ArrayList<>();
|
|
||||||
if (creationTimestampOrder != null) {
|
|
||||||
Comparator<Notification> comparator =
|
|
||||||
comparing(notification -> notification.getMetadata().getCreationTimestamp());
|
|
||||||
if (creationTimestampOrder.isDescending()) {
|
|
||||||
comparator = comparator.reversed();
|
|
||||||
}
|
|
||||||
comparators.add(comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
comparators.add(Comparators.defaultComparator());
|
|
||||||
return comparators.stream()
|
|
||||||
.reduce(Comparator::thenComparing)
|
|
||||||
.orElse(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,8 +143,8 @@ public class UserNotificationEndpoint implements CustomEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ServerResponse> listNotification(ServerRequest request) {
|
private Mono<ServerResponse> listNotification(ServerRequest request) {
|
||||||
var query = new UserNotificationQuery(request.exchange());
|
|
||||||
var username = request.pathVariable("username");
|
var username = request.pathVariable("username");
|
||||||
|
var query = new UserNotificationQuery(request.exchange(), username);
|
||||||
return notificationService.listByUser(username, query)
|
return notificationService.listByUser(username, query)
|
||||||
.flatMap(notifications -> ServerResponse.ok().bodyValue(notifications));
|
.flatMap(notifications -> ServerResponse.ok().bodyValue(notifications));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -362,63 +361,8 @@ class DefaultNotificationCenterTest {
|
||||||
verify(notificationTemplateSelector).select(eq(reasonTypeName), any());
|
verify(notificationTemplateSelector).select(eq(reasonTypeName), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
void listSubscriptionTest() {
|
|
||||||
var subscriptions = createSubscriptions();
|
|
||||||
|
|
||||||
when(client.list(eq(Subscription.class), any(Predicate.class), any()))
|
|
||||||
.thenAnswer(answer -> {
|
|
||||||
var predicate = (Predicate<Subscription>) answer.getArgument(1, Predicate.class);
|
|
||||||
return Flux.fromIterable(subscriptions)
|
|
||||||
.filter(predicate);
|
|
||||||
});
|
|
||||||
|
|
||||||
var subscription = subscriptions.get(0);
|
|
||||||
var subscriber = subscription.getSpec().getSubscriber();
|
|
||||||
notificationCenter.listSubscription(subscriber)
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.expectNext(subscription)
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
verify(client).list(eq(Subscription.class), any(Predicate.class), any());
|
|
||||||
|
|
||||||
var otherSubscriber = JsonUtils.deepCopy(subscriber);
|
|
||||||
otherSubscriber.setName("other");
|
|
||||||
notificationCenter.listSubscription(otherSubscriber)
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
void listObserversTest() {
|
|
||||||
var subscriptions = createSubscriptions();
|
|
||||||
|
|
||||||
when(client.list(eq(Subscription.class), any(Predicate.class), any()))
|
|
||||||
.thenAnswer(answer -> {
|
|
||||||
var predicate = (Predicate<Subscription>) answer.getArgument(1, Predicate.class);
|
|
||||||
return Flux.fromIterable(subscriptions)
|
|
||||||
.filter(predicate);
|
|
||||||
});
|
|
||||||
|
|
||||||
var subscription = subscriptions.get(0);
|
|
||||||
var reasonTypeName = subscription.getSpec().getReason().getReasonType();
|
|
||||||
var reasonSubject = subscription.getSpec().getReason().getSubject();
|
|
||||||
notificationCenter.listObservers(reasonTypeName, reasonSubject)
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.expectNext(subscription)
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
verify(client).list(eq(Subscription.class), any(Predicate.class), any());
|
|
||||||
|
|
||||||
notificationCenter.listObservers("other-reason", reasonSubject)
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
void listObserverWhenDuplicateSubscribers() {
|
void listObserverWhenDuplicateSubscribers() {
|
||||||
var sourceSubscriptions = createSubscriptions();
|
var sourceSubscriptions = createSubscriptions();
|
||||||
var subscriptionA = sourceSubscriptions.get(0);
|
var subscriptionA = sourceSubscriptions.get(0);
|
||||||
|
@ -427,26 +371,11 @@ class DefaultNotificationCenterTest {
|
||||||
var subscriptionC = JsonUtils.deepCopy(subscriptionA);
|
var subscriptionC = JsonUtils.deepCopy(subscriptionA);
|
||||||
subscriptionC.getSpec().getReason().getSubject().setName(null);
|
subscriptionC.getSpec().getReason().getSubject().setName(null);
|
||||||
|
|
||||||
var subscriptions = List.of(subscriptionA, subscriptionB, subscriptionC);
|
var subscriptions = Flux.just(subscriptionA, subscriptionB, subscriptionC);
|
||||||
when(client.list(eq(Subscription.class), any(Predicate.class), any()))
|
|
||||||
.thenAnswer(answer -> {
|
|
||||||
var predicate = (Predicate<Subscription>) answer.getArgument(1, Predicate.class);
|
|
||||||
return Flux.fromIterable(subscriptions)
|
|
||||||
.filter(predicate);
|
|
||||||
});
|
|
||||||
|
|
||||||
var subscription = subscriptions.get(0);
|
DefaultNotificationCenter.distinctByKey(subscriptions)
|
||||||
var reasonTypeName = subscription.getSpec().getReason().getReasonType();
|
|
||||||
var reasonSubject = subscription.getSpec().getReason().getSubject();
|
|
||||||
notificationCenter.listObservers(reasonTypeName, reasonSubject)
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.expectNext(subscription)
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
verify(client).list(eq(Subscription.class), any(Predicate.class), any());
|
|
||||||
|
|
||||||
notificationCenter.listObservers("other-reason", reasonSubject)
|
|
||||||
.as(StepVerifier::create)
|
.as(StepVerifier::create)
|
||||||
|
.expectNext(subscriptionA)
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
import run.halo.app.core.extension.notification.NotificationTemplate;
|
import run.halo.app.core.extension.notification.NotificationTemplate;
|
||||||
|
@ -41,7 +42,7 @@ class ReasonNotificationTemplateSelectorImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void select() {
|
void select() {
|
||||||
when(client.list(eq(NotificationTemplate.class), any(), any()))
|
when(client.listAll(eq(NotificationTemplate.class), any(), any(Sort.class)))
|
||||||
.thenReturn(Flux.fromIterable(templates()));
|
.thenReturn(Flux.fromIterable(templates()));
|
||||||
// language priority: zh_CN -> zh -> default
|
// language priority: zh_CN -> zh -> default
|
||||||
// if language is same, then compare creationTimestamp to get the latest one
|
// if language is same, then compare creationTimestamp to get the latest one
|
||||||
|
|
|
@ -28,7 +28,7 @@ const {
|
||||||
username: currentUser?.metadata.name as string,
|
username: currentUser?.metadata.name as string,
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 20,
|
size: 20,
|
||||||
unRead: true,
|
fieldSelector: ["spec.unread=true"],
|
||||||
});
|
});
|
||||||
|
|
||||||
return data.items;
|
return data.items;
|
||||||
|
|
|
@ -229,6 +229,7 @@ models/reason-type-spec.ts
|
||||||
models/reason-type.ts
|
models/reason-type.ts
|
||||||
models/reason.ts
|
models/reason.ts
|
||||||
models/ref.ts
|
models/ref.ts
|
||||||
|
models/register-verify-email-request.ts
|
||||||
models/reply-list.ts
|
models/reply-list.ts
|
||||||
models/reply-request.ts
|
models/reply-request.ts
|
||||||
models/reply-spec.ts
|
models/reply-spec.ts
|
||||||
|
|
|
@ -36,7 +36,6 @@ import {
|
||||||
RequestArgs,
|
RequestArgs,
|
||||||
BaseAPI,
|
BaseAPI,
|
||||||
RequiredError,
|
RequiredError,
|
||||||
operationServerMap,
|
|
||||||
} from "../base";
|
} from "../base";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { PasswordResetEmailRequest } from "../models";
|
import { PasswordResetEmailRequest } from "../models";
|
||||||
|
@ -48,7 +47,6 @@ import { ResetPasswordRequest } from "../models";
|
||||||
import { SignUpRequest } from "../models";
|
import { SignUpRequest } from "../models";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { User } from "../models";
|
import { User } from "../models";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ApiHaloRunV1alpha1UserApi - axios parameter creator
|
* ApiHaloRunV1alpha1UserApi - axios parameter creator
|
||||||
* @export
|
* @export
|
||||||
|
@ -338,18 +336,12 @@ export const ApiHaloRunV1alpha1UserApiFp = function (
|
||||||
resetPasswordRequest,
|
resetPasswordRequest,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
return createRequestFunction(
|
||||||
const operationBasePath =
|
localVarAxiosArgs,
|
||||||
operationServerMap["ApiHaloRunV1alpha1UserApi.resetPasswordByToken"]?.[
|
globalAxios,
|
||||||
index
|
BASE_PATH,
|
||||||
]?.url;
|
configuration
|
||||||
return (axios, basePath) =>
|
);
|
||||||
createRequestFunction(
|
|
||||||
localVarAxiosArgs,
|
|
||||||
globalAxios,
|
|
||||||
BASE_PATH,
|
|
||||||
configuration
|
|
||||||
)(axios, operationBasePath || basePath);
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Send password reset email when forgot password
|
* Send password reset email when forgot password
|
||||||
|
@ -368,18 +360,12 @@ export const ApiHaloRunV1alpha1UserApiFp = function (
|
||||||
passwordResetEmailRequest,
|
passwordResetEmailRequest,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
return createRequestFunction(
|
||||||
const operationBasePath =
|
localVarAxiosArgs,
|
||||||
operationServerMap[
|
globalAxios,
|
||||||
"ApiHaloRunV1alpha1UserApi.sendPasswordResetEmail"
|
BASE_PATH,
|
||||||
]?.[index]?.url;
|
configuration
|
||||||
return (axios, basePath) =>
|
);
|
||||||
createRequestFunction(
|
|
||||||
localVarAxiosArgs,
|
|
||||||
globalAxios,
|
|
||||||
BASE_PATH,
|
|
||||||
configuration
|
|
||||||
)(axios, operationBasePath || basePath);
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Send registration verification email, which can be called when mustVerifyEmailOnRegistration in user settings is true
|
* Send registration verification email, which can be called when mustVerifyEmailOnRegistration in user settings is true
|
||||||
|
@ -398,18 +384,12 @@ export const ApiHaloRunV1alpha1UserApiFp = function (
|
||||||
registerVerifyEmailRequest,
|
registerVerifyEmailRequest,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
return createRequestFunction(
|
||||||
const operationBasePath =
|
localVarAxiosArgs,
|
||||||
operationServerMap[
|
globalAxios,
|
||||||
"ApiHaloRunV1alpha1UserApi.sendRegisterVerifyEmail"
|
BASE_PATH,
|
||||||
]?.[index]?.url;
|
configuration
|
||||||
return (axios, basePath) =>
|
);
|
||||||
createRequestFunction(
|
|
||||||
localVarAxiosArgs,
|
|
||||||
globalAxios,
|
|
||||||
BASE_PATH,
|
|
||||||
configuration
|
|
||||||
)(axios, operationBasePath || basePath);
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Sign up a new user
|
* Sign up a new user
|
||||||
|
@ -427,16 +407,12 @@ export const ApiHaloRunV1alpha1UserApiFp = function (
|
||||||
signUpRequest,
|
signUpRequest,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
const index = configuration?.serverIndex ?? 0;
|
return createRequestFunction(
|
||||||
const operationBasePath =
|
localVarAxiosArgs,
|
||||||
operationServerMap["ApiHaloRunV1alpha1UserApi.signUp"]?.[index]?.url;
|
globalAxios,
|
||||||
return (axios, basePath) =>
|
BASE_PATH,
|
||||||
createRequestFunction(
|
configuration
|
||||||
localVarAxiosArgs,
|
);
|
||||||
globalAxios,
|
|
||||||
BASE_PATH,
|
|
||||||
configuration
|
|
||||||
)(axios, operationBasePath || basePath);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -176,10 +176,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiAxiosParamCreator =
|
||||||
* @param {string} [keyword]
|
* @param {string} [keyword]
|
||||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||||
* @param {number} [page] The page number. Zero indicates no page.
|
* @param {number} [page] The page number. Zero indicates no page.
|
||||||
* @param {string} [reason] Filter by notification reason
|
|
||||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: metadata.creationTimestamp
|
||||||
* @param {boolean} [unRead] true for unread, false for read, null for all
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
|
@ -189,10 +187,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiAxiosParamCreator =
|
||||||
keyword?: string,
|
keyword?: string,
|
||||||
labelSelector?: Array<string>,
|
labelSelector?: Array<string>,
|
||||||
page?: number,
|
page?: number,
|
||||||
reason?: string,
|
|
||||||
size?: number,
|
size?: number,
|
||||||
sort?: Array<string>,
|
sort?: Array<string>,
|
||||||
unRead?: boolean,
|
|
||||||
options: AxiosRequestConfig = {}
|
options: AxiosRequestConfig = {}
|
||||||
): Promise<RequestArgs> => {
|
): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'username' is not null or undefined
|
// verify required parameter 'username' is not null or undefined
|
||||||
|
@ -241,10 +237,6 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiAxiosParamCreator =
|
||||||
localVarQueryParameter["page"] = page;
|
localVarQueryParameter["page"] = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason !== undefined) {
|
|
||||||
localVarQueryParameter["reason"] = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size !== undefined) {
|
if (size !== undefined) {
|
||||||
localVarQueryParameter["size"] = size;
|
localVarQueryParameter["size"] = size;
|
||||||
}
|
}
|
||||||
|
@ -253,10 +245,6 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiAxiosParamCreator =
|
||||||
localVarQueryParameter["sort"] = Array.from(sort);
|
localVarQueryParameter["sort"] = Array.from(sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unRead !== undefined) {
|
|
||||||
localVarQueryParameter["unRead"] = unRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
let headersFromBaseOptions =
|
let headersFromBaseOptions =
|
||||||
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
@ -540,10 +528,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiFp = function (
|
||||||
* @param {string} [keyword]
|
* @param {string} [keyword]
|
||||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||||
* @param {number} [page] The page number. Zero indicates no page.
|
* @param {number} [page] The page number. Zero indicates no page.
|
||||||
* @param {string} [reason] Filter by notification reason
|
|
||||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||||
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp
|
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: metadata.creationTimestamp
|
||||||
* @param {boolean} [unRead] true for unread, false for read, null for all
|
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
|
@ -553,10 +539,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiFp = function (
|
||||||
keyword?: string,
|
keyword?: string,
|
||||||
labelSelector?: Array<string>,
|
labelSelector?: Array<string>,
|
||||||
page?: number,
|
page?: number,
|
||||||
reason?: string,
|
|
||||||
size?: number,
|
size?: number,
|
||||||
sort?: Array<string>,
|
sort?: Array<string>,
|
||||||
unRead?: boolean,
|
|
||||||
options?: AxiosRequestConfig
|
options?: AxiosRequestConfig
|
||||||
): Promise<
|
): Promise<
|
||||||
(
|
(
|
||||||
|
@ -571,10 +555,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiFp = function (
|
||||||
keyword,
|
keyword,
|
||||||
labelSelector,
|
labelSelector,
|
||||||
page,
|
page,
|
||||||
reason,
|
|
||||||
size,
|
size,
|
||||||
sort,
|
sort,
|
||||||
unRead,
|
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
return createRequestFunction(
|
return createRequestFunction(
|
||||||
|
@ -732,10 +714,8 @@ export const ApiNotificationHaloRunV1alpha1NotificationApiFactory = function (
|
||||||
requestParameters.keyword,
|
requestParameters.keyword,
|
||||||
requestParameters.labelSelector,
|
requestParameters.labelSelector,
|
||||||
requestParameters.page,
|
requestParameters.page,
|
||||||
requestParameters.reason,
|
|
||||||
requestParameters.size,
|
requestParameters.size,
|
||||||
requestParameters.sort,
|
requestParameters.sort,
|
||||||
requestParameters.unRead,
|
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
.then((request) => request(axios, basePath));
|
.then((request) => request(axios, basePath));
|
||||||
|
@ -873,13 +853,6 @@ export interface ApiNotificationHaloRunV1alpha1NotificationApiListUserNotificati
|
||||||
*/
|
*/
|
||||||
readonly page?: number;
|
readonly page?: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter by notification reason
|
|
||||||
* @type {string}
|
|
||||||
* @memberof ApiNotificationHaloRunV1alpha1NotificationApiListUserNotifications
|
|
||||||
*/
|
|
||||||
readonly reason?: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of one page. Zero indicates no limit.
|
* Size of one page. Zero indicates no limit.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
|
@ -888,18 +861,11 @@ export interface ApiNotificationHaloRunV1alpha1NotificationApiListUserNotificati
|
||||||
readonly size?: number;
|
readonly size?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort property and direction of the list result. Supported fields: creationTimestamp
|
* Sort property and direction of the list result. Supported fields: metadata.creationTimestamp
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
* @memberof ApiNotificationHaloRunV1alpha1NotificationApiListUserNotifications
|
* @memberof ApiNotificationHaloRunV1alpha1NotificationApiListUserNotifications
|
||||||
*/
|
*/
|
||||||
readonly sort?: Array<string>;
|
readonly sort?: Array<string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* true for unread, false for read, null for all
|
|
||||||
* @type {boolean}
|
|
||||||
* @memberof ApiNotificationHaloRunV1alpha1NotificationApiListUserNotifications
|
|
||||||
*/
|
|
||||||
readonly unRead?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1026,10 +992,8 @@ export class ApiNotificationHaloRunV1alpha1NotificationApi extends BaseAPI {
|
||||||
requestParameters.keyword,
|
requestParameters.keyword,
|
||||||
requestParameters.labelSelector,
|
requestParameters.labelSelector,
|
||||||
requestParameters.page,
|
requestParameters.page,
|
||||||
requestParameters.reason,
|
|
||||||
requestParameters.size,
|
requestParameters.size,
|
||||||
requestParameters.sort,
|
requestParameters.sort,
|
||||||
requestParameters.unRead,
|
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
.then((request) => request(this.axios, this.basePath));
|
.then((request) => request(this.axios, this.basePath));
|
||||||
|
|
|
@ -73,16 +73,3 @@ export class RequiredError extends Error {
|
||||||
this.name = "RequiredError";
|
this.name = "RequiredError";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServerMap {
|
|
||||||
[key: string]: {
|
|
||||||
url: string,
|
|
||||||
description: string,
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
*/
|
|
||||||
export const operationServerMap: ServerMap = {};
|
|
||||||
|
|
|
@ -13,12 +13,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface ConfigurationParameters {
|
export interface ConfigurationParameters {
|
||||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
apiKey?:
|
||||||
|
| string
|
||||||
|
| Promise<string>
|
||||||
|
| ((name: string) => string)
|
||||||
|
| ((name: string) => Promise<string>);
|
||||||
username?: string;
|
username?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
accessToken?:
|
||||||
|
| string
|
||||||
|
| Promise<string>
|
||||||
|
| ((name?: string, scopes?: string[]) => string)
|
||||||
|
| ((name?: string, scopes?: string[]) => Promise<string>);
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
serverIndex?: number;
|
|
||||||
baseOptions?: any;
|
baseOptions?: any;
|
||||||
formDataCtor?: new () => any;
|
formDataCtor?: new () => any;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +36,11 @@ export class Configuration {
|
||||||
* @param name security name
|
* @param name security name
|
||||||
* @memberof Configuration
|
* @memberof Configuration
|
||||||
*/
|
*/
|
||||||
apiKey?: string | Promise<string> | ((name: string) => string) | ((name: string) => Promise<string>);
|
apiKey?:
|
||||||
|
| string
|
||||||
|
| Promise<string>
|
||||||
|
| ((name: string) => string)
|
||||||
|
| ((name: string) => Promise<string>);
|
||||||
/**
|
/**
|
||||||
* parameter for basic security
|
* parameter for basic security
|
||||||
*
|
*
|
||||||
|
@ -50,7 +61,11 @@ export class Configuration {
|
||||||
* @param scopes oauth2 scope
|
* @param scopes oauth2 scope
|
||||||
* @memberof Configuration
|
* @memberof Configuration
|
||||||
*/
|
*/
|
||||||
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise<string>);
|
accessToken?:
|
||||||
|
| string
|
||||||
|
| Promise<string>
|
||||||
|
| ((name?: string, scopes?: string[]) => string)
|
||||||
|
| ((name?: string, scopes?: string[]) => Promise<string>);
|
||||||
/**
|
/**
|
||||||
* override base path
|
* override base path
|
||||||
*
|
*
|
||||||
|
@ -58,13 +73,6 @@ export class Configuration {
|
||||||
* @memberof Configuration
|
* @memberof Configuration
|
||||||
*/
|
*/
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
/**
|
|
||||||
* override server index
|
|
||||||
*
|
|
||||||
* @type {number}
|
|
||||||
* @memberof Configuration
|
|
||||||
*/
|
|
||||||
serverIndex?: number;
|
|
||||||
/**
|
/**
|
||||||
* base options for axios calls
|
* base options for axios calls
|
||||||
*
|
*
|
||||||
|
@ -87,7 +95,6 @@ export class Configuration {
|
||||||
this.password = param.password;
|
this.password = param.password;
|
||||||
this.accessToken = param.accessToken;
|
this.accessToken = param.accessToken;
|
||||||
this.basePath = param.basePath;
|
this.basePath = param.basePath;
|
||||||
this.serverIndex = param.serverIndex;
|
|
||||||
this.baseOptions = param.baseOptions;
|
this.baseOptions = param.baseOptions;
|
||||||
this.formDataCtor = param.formDataCtor;
|
this.formDataCtor = param.formDataCtor;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +110,14 @@ export class Configuration {
|
||||||
* @return True if the given MIME is JSON, false otherwise.
|
* @return True if the given MIME is JSON, false otherwise.
|
||||||
*/
|
*/
|
||||||
public isJsonMime(mime: string): boolean {
|
public isJsonMime(mime: string): boolean {
|
||||||
const jsonMime: RegExp = new RegExp("^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$", "i");
|
const jsonMime: RegExp = new RegExp(
|
||||||
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === "application/json-patch+json");
|
"^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$",
|
||||||
|
"i"
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
mime !== null &&
|
||||||
|
(jsonMime.test(mime) ||
|
||||||
|
mime.toLowerCase() === "application/json-patch+json")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@ import { User } from "./user";
|
||||||
export interface SignUpRequest {
|
export interface SignUpRequest {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {any}
|
* @type {string}
|
||||||
* @memberof SignUpRequest
|
* @memberof SignUpRequest
|
||||||
*/
|
*/
|
||||||
password: any;
|
password: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {User}
|
* @type {User}
|
||||||
|
@ -36,8 +36,8 @@ export interface SignUpRequest {
|
||||||
user: User;
|
user: User;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {any}
|
* @type {string}
|
||||||
* @memberof SignUpRequest
|
* @memberof SignUpRequest
|
||||||
*/
|
*/
|
||||||
verifyCode?: any;
|
verifyCode?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ const {
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiClient.notification.listUserNotifications({
|
const { data } = await apiClient.notification.listUserNotifications({
|
||||||
username: currentUser?.metadata.name as string,
|
username: currentUser?.metadata.name as string,
|
||||||
unRead: activeTab.value === "unread",
|
fieldSelector: [`spec.unread=${activeTab.value === "unread"}`],
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
Loading…
Reference in New Issue