TD-666: New api keys protocol (#134)

This commit is contained in:
Rinat Arsaev 2023-07-18 12:21:18 +04:00 committed by GitHub
parent 08d5eb406d
commit e4f63bacd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 102 additions and 63 deletions

22
package-lock.json generated
View File

@ -25,9 +25,9 @@
"@sentry/angular": "^7.56.0",
"@sentry/integrations": "^7.56.0",
"@sentry/tracing": "^7.56.0",
"@vality/ng-core": "^16.1.2-pr-28-02fc769.0",
"@vality/ng-core": "^16.2.1-pr-33-42d91a3.0",
"@vality/swag-anapi-v2": "2.0.0",
"@vality/swag-api-keys": "1.0.1-55db9ab.0",
"@vality/swag-api-keys-v2": "^0.1.2-be3bbdd.0",
"@vality/swag-claim-management": "0.1.1-7a03f9b.0",
"@vality/swag-organizations": "1.0.1-cd6cc10.0",
"@vality/swag-payments": "0.1.1-01da4bb.0",
@ -6866,9 +6866,9 @@
}
},
"node_modules/@vality/ng-core": {
"version": "16.1.2-pr-28-02fc769.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-16.1.2-pr-28-02fc769.0.tgz",
"integrity": "sha512-OKr+iYvZoxV6JX2t68UtYlf+GV4S3e4aiJ0/tAbK2A5hKn+DmdxNhUG32dGhh12oDqGWodGSuiqS1HT62FLmBg==",
"version": "16.2.1-pr-33-42d91a3.0",
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-16.2.1-pr-33-42d91a3.0.tgz",
"integrity": "sha512-Ags1PPyLkeHEmjRlh3hqgo8jR4dtLpnM9EmjZ3Qa33ayfI8cki+BQANRzaH2VOgjTLcwR54QOTxm012xui2SEQ==",
"dependencies": {
"@ng-matero/extensions": "^16.0.0",
"@s-libs/js-core": "^16.0.0",
@ -6970,16 +6970,16 @@
"@angular/core": "^16.1.0"
}
},
"node_modules/@vality/swag-api-keys": {
"version": "1.0.1-55db9ab.0",
"resolved": "https://registry.npmjs.org/@vality/swag-api-keys/-/swag-api-keys-1.0.1-55db9ab.0.tgz",
"integrity": "sha512-pafXHEIKv8o8GFQPA82PwQhy0XgWyHbrRqMnemyUyzLFFeTIJ/pwevfUGajzohUUg2I66mQ2utu8lVPw4485rg==",
"node_modules/@vality/swag-api-keys-v2": {
"version": "0.1.2-be3bbdd.0",
"resolved": "https://registry.npmjs.org/@vality/swag-api-keys-v2/-/swag-api-keys-v2-0.1.2-be3bbdd.0.tgz",
"integrity": "sha512-PD8nH0AqT/KjSFsEYrs27CAg0iN8VTjLxgjgkhnDeLy4V6AVqJ12MVHQeTGhmJTOnpQNp7sLHVPLSGYgzvvayg==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=14.0.0",
"@angular/core": ">=14.0.0"
"@angular/common": "^13.0.0",
"@angular/core": "^13.0.0"
}
},
"node_modules/@vality/swag-claim-management": {

View File

@ -40,9 +40,9 @@
"@sentry/angular": "^7.56.0",
"@sentry/integrations": "^7.56.0",
"@sentry/tracing": "^7.56.0",
"@vality/ng-core": "^16.1.2-pr-28-02fc769.0",
"@vality/ng-core": "^16.2.1-pr-33-42d91a3.0",
"@vality/swag-anapi-v2": "2.0.0",
"@vality/swag-api-keys": "1.0.1-55db9ab.0",
"@vality/swag-api-keys-v2": "^0.1.2-be3bbdd.0",
"@vality/swag-claim-management": "0.1.1-7a03f9b.0",
"@vality/swag-organizations": "1.0.1-cd6cc10.0",
"@vality/swag-payments": "0.1.1-01da4bb.0",

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core';
import { Configuration } from '@vality/swag-api-keys';
import { Configuration } from '@vality/swag-api-keys-v2';
import { ConfigService } from '../../config';
@ -9,7 +9,7 @@ import { ConfigService } from '../../config';
provide: Configuration,
deps: [ConfigService],
useFactory: (configService: ConfigService) =>
new Configuration({ basePath: `${configService.apiEndpoint}/apikeys/v1` }),
new Configuration({ basePath: `${configService.apiEndpoint}/apikeys/v2` }),
},
],
})

View File

@ -1,10 +1,18 @@
import { Injectable } from '@angular/core';
import { ApiKeysService as ApiService } from '@vality/swag-api-keys';
import { Injectable, Injector } from '@angular/core';
import { ApiKeysService as ApiService } from '@vality/swag-api-keys-v2';
import { createApi } from '../utils';
import { PartyIdExtension } from '../utils/extensions';
import { PartyIdExtension, PartyIdPatchMethodService } from '../utils/extensions';
@Injectable({
providedIn: 'root',
})
export class ApiKeysService extends createApi(ApiService, [PartyIdExtension]) {}
export class ApiKeysService extends createApi(ApiService, [PartyIdExtension]) {
constructor(injector: Injector, partyIdPatchMethodService: PartyIdPatchMethodService) {
super(injector);
this.requestRevokeApiKey = partyIdPatchMethodService.patch(
this.requestRevokeApiKey,
(params, partyId) => (params.partyId = partyId)
);
}
}

View File

@ -1,9 +1,9 @@
import { Injectable } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ApiKey } from '@vality/swag-api-keys';
import { ApiKey } from '@vality/swag-api-keys-v2';
import { Observable } from 'rxjs';
import { ExpandedIdManager } from '@dsh/app/shared/services';
import { ExpandedIdManager, Fragment } from '@dsh/app/shared/services';
import { FetchApiKeysService } from './fetch-api-keys.service';
@ -17,7 +17,15 @@ export class ApiKeysExpandedIdManager extends ExpandedIdManager<ApiKey> {
super(route, router);
}
protected toFragment(apiKey: ApiKey): Fragment {
return apiKey.id;
}
protected fragmentNotFound(): void {
this.fetchApiKeysService.more();
}
protected get dataSet$(): Observable<ApiKey[]> {
return this.fetchApiKeysService.apiKeys$;
return this.fetchApiKeysService.result$;
}
}

View File

@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { UntilDestroy } from '@ngneat/until-destroy';
import { DialogService } from '@vality/ng-core';
import { ApiKey } from '@vality/swag-api-keys';
import { ApiKey } from '@vality/swag-api-keys-v2';
import { ApiKeyDeleteDialogComponent } from './components/api-key-delete-dialog/api-key-delete-dialog.component';

View File

@ -3,7 +3,7 @@ import { FlexModule } from '@angular/flex-layout';
import { TranslocoModule } from '@ngneat/transloco';
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
import { DialogSuperclass } from '@vality/ng-core';
import { RequestRevokeApiKeyRequestParams } from '@vality/swag-api-keys';
import { RequestRevokeApiKeyRequestParams } from '@vality/swag-api-keys-v2';
import { ApiKeysService } from '@dsh/app/api/api-keys';
import { BaseDialogModule } from '@dsh/app/shared/components/dialog/base-dialog';
@ -34,7 +34,7 @@ export class ApiKeyDeleteDialogComponent extends DialogSuperclass<
confirm() {
this.apiKeysService
.requestRevokeApiKey(this.dialogData)
.requestRevokeApiKey({ ...this.dialogData, status: 'Revoked' })
.pipe(untilDestroyed(this))
.subscribe({
next: () => {

View File

@ -32,5 +32,6 @@
*ngIf="(apiKeys$ | async)?.length === 0"
[text]="t('emptyResult')"
></dsh-empty-search-result>
<dsh-show-more-panel *ngIf="hasMore$ | async" (showMore)="more()"></dsh-show-more-panel>
</ng-template>
</div>

View File

@ -1,13 +1,14 @@
import { Component } from '@angular/core';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { DialogService } from '@vality/ng-core';
import { ApiKeyStatus, ListApiKeysRequestParams } from '@vality/swag-api-keys';
import { ApiKeyStatus } from '@vality/swag-api-keys-v2';
import { ApiKeyCreateDialogComponent } from '@dsh/app/sections/payment-section/integrations/api-keys/components/api-key-create-dialog/api-key-create-dialog.component';
import { mapToTimestamp, shareReplayRefCount } from '@dsh/app/custom-operators';
import { QueryParamsService } from '@dsh/app/shared';
import { ApiKeysExpandedIdManager } from './api-keys-expanded-id-manager.service';
import { ApiKeyCreateDialogComponent } from './components/api-key-create-dialog/api-key-create-dialog.component';
import { FetchApiKeysService } from './fetch-api-keys.service';
import { QueryParamsService } from '../../../../shared';
@UntilDestroy()
@Component({
@ -17,20 +18,27 @@ import { QueryParamsService } from '../../../../shared';
})
export class ApiKeysComponent {
showInactive = this.qp.params.showInactive;
apiKeys$ = this.fetchApiKeysService.apiKeys$;
apiKeys$ = this.fetchApiKeysService.result$;
isLoading$ = this.fetchApiKeysService.isLoading$;
hasMore$ = this.fetchApiKeysService.hasMore$;
expandedId$ = this.apiKeysExpandedIdManager.expandedId$;
lastUpdated$ = this.fetchApiKeysService.lastUpdated$;
lastUpdated$ = this.fetchApiKeysService.result$.pipe(mapToTimestamp, shareReplayRefCount());
constructor(
private qp: QueryParamsService<{ showInactive: boolean }>,
private apiKeysExpandedIdManager: ApiKeysExpandedIdManager,
private fetchApiKeysService: FetchApiKeysService,
private dialogService: DialogService
) {}
) {
this.update();
}
update(params: Omit<ListApiKeysRequestParams, 'partyId' | 'xRequestID'> = {}) {
this.fetchApiKeysService.update(Object.assign(params, !this.showInactive && { status: ApiKeyStatus.Active }));
update() {
this.fetchApiKeysService.load(Object.assign({}, !this.showInactive && { status: ApiKeyStatus.Active }));
}
more() {
this.fetchApiKeysService.more();
}
create() {

View File

@ -10,6 +10,7 @@ import { ButtonModule } from '@dsh/components/buttons';
import { EmptySearchResultModule } from '@dsh/components/empty-search-result';
import { SpinnerModule } from '@dsh/components/indicators';
import { CardModule } from '@dsh/components/layout';
import { ShowMorePanelModule } from '@dsh/components/show-more-panel';
import { ApiKeysListModule } from './api-keys-list/api-keys-list.module';
import { ApiKeysRoutingModule } from './api-keys-routing.module';
@ -33,6 +34,7 @@ import { ApiKeyRevokeComponent } from './components/api-key-revoke/api-key-revok
MatSlideToggleModule,
ApiKeysListModule,
ApiKeyCreateDialogComponent,
ShowMorePanelModule,
],
})
export class ApiKeysModule {}

View File

@ -50,11 +50,11 @@ export class ApiKeyCreateDialogComponent extends DialogSuperclass<ApiKeyCreateDi
confirm() {
this.apiKeysService
.issueApiKey()
.issueApiKey({ apiKeyIssue: { name: this.form.value.name } })
.pipe(untilDestroyed(this))
.subscribe({
next: (res) => {
this.apiKey = res.accessToken;
this.apiKey = res.apiKey;
},
error: (err) => {
this.errorService.error(err);

View File

@ -1,37 +1,43 @@
import { Injectable } from '@angular/core';
import { ListApiKeysRequestParams } from '@vality/swag-api-keys';
import { BehaviorSubject, Observable, defer, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { TranslocoService } from '@ngneat/transloco';
import { FetchSuperclass, NotifyLogService, FetchResult, FetchOptions } from '@vality/ng-core';
import { ListApiKeysRequestParams } from '@vality/swag-api-keys-v2';
import { ApiKey } from '@vality/swag-api-keys-v2/lib/model/api-key';
import { of, Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { ApiKeysService } from '@dsh/app/api/api-keys';
import { mapToTimestamp, shareReplayRefCount } from '@dsh/app/custom-operators';
import { ErrorService } from '@dsh/app/shared/services';
import { inProgressFrom, progressTo } from '@dsh/utils';
@Injectable()
export class FetchApiKeysService {
apiKeys$ = defer(() => this.fetchApiKeys$).pipe(
switchMap((p) =>
this.apiKeysService.listApiKeys(p).pipe(
map((r) => r.results),
progressTo(() => this.progress$),
export class FetchApiKeysService extends FetchSuperclass<
ApiKey,
Omit<ListApiKeysRequestParams, 'partyId' | 'xRequestID' | 'limit'>
> {
constructor(
private apiKeysService: ApiKeysService,
private logService: NotifyLogService,
private transloco: TranslocoService
) {
super();
}
protected fetch(
params: Omit<ListApiKeysRequestParams, 'partyId' | 'xRequestID' | 'limit'>,
options: FetchOptions
): Observable<FetchResult<ApiKey>> {
return this.apiKeysService
.listApiKeys({ ...params, limit: options.size, continuationToken: options.continuationToken })
.pipe(
map((res) => ({
result: res.results,
continuationToken: res.continuationToken,
})),
catchError((err) => {
this.errorService.error(err);
return of([]);
this.logService.error(err, this.transloco.translate('apiKeys.fetch.error', {}, 'payment-section'));
return of({
result: [],
});
})
)
),
shareReplayRefCount()
);
isLoading$ = inProgressFrom(() => this.progress$, this.apiKeys$);
lastUpdated$: Observable<string> = this.apiKeys$.pipe(mapToTimestamp, shareReplayRefCount());
private progress$ = new BehaviorSubject(0);
private fetchApiKeys$ = new BehaviorSubject<Omit<ListApiKeysRequestParams, 'partyId' | 'xRequestID'>>({});
constructor(private apiKeysService: ApiKeysService, private errorService: ErrorService) {}
update(params: Omit<ListApiKeysRequestParams, 'partyId' | 'xRequestID'> = {}) {
this.fetchApiKeys$.next(params);
);
}
}

View File

@ -38,6 +38,9 @@
"title": "Key revocation request"
},
"emptyResult": "No keys released",
"fetch": {
"error": "Error loading keys"
},
"list": {
"createdAt": "Created at",
"delete": "Revoke key",

View File

@ -38,6 +38,9 @@
"title": "Запрос на отзыв ключа"
},
"emptyResult": "Не выпущено ни одного ключа",
"fetch": {
"error": "Ошибка при загрузке ключей"
},
"list": {
"createdAt": "Создан",
"delete": "Удалить",