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
guqing 2024-02-27 19:53:13 +08:00 committed by GitHub
parent d2f569699b
commit 11114416fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 242 additions and 300 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
} }

View File

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

View File

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

View File

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

View File

@ -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);
}, },
}; };
}; };

View File

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

View File

@ -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 = {};

View File

@ -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")
);
} }
} }

View File

@ -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;
} }

View File

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