OPS-182: Support wachter API, refactor & remove unused thrift (#142)

This commit is contained in:
Rinat Arsaev 2022-09-25 19:49:45 +03:00 committed by GitHub
parent 11cc97ecf6
commit dceaf7b920
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 349 additions and 409 deletions

View File

@ -1,21 +1,27 @@
require('dotenv').config({ path: ['.env', process.env.NODE_ENV].filter(Boolean).join('.') });
const THRIFT_PROXY_CONFIG = {
context: [
'/v1',
'/v3',
'/stat',
'/fistful',
'/file_storage',
'/deanonimus',
'/payout/management',
],
target: process.env.PROXY_TARGET,
secure: false,
logLevel: 'debug',
changeOrigin: true,
};
const { PROXY_TARGET } = process.env;
const REQUIRED_ENV = [PROXY_TARGET];
if (!THRIFT_PROXY_CONFIG.target) throw new Error('proxy.conf.js - set the thrift proxy target!');
if (REQUIRED_ENV.findIndex((e) => !e) !== -1) {
throw new Error('[proxy.conf.js] Set required environment variables!');
}
module.exports = [THRIFT_PROXY_CONFIG];
module.exports = [
{
context: [
'/v1',
'/v3',
'/stat',
'/fistful',
'/file_storage',
'/deanonimus',
'/payout/management',
'/wachter',
],
target: PROXY_TARGET,
secure: false,
logLevel: 'debug',
changeOrigin: true,
},
];

View File

@ -3,10 +3,14 @@ import { Observable } from 'rxjs';
import { ThriftApi } from './thrift-api';
import { ThriftApiArgs } from './types/thrift-api-args';
export function createThriftApi<T extends Record<PropertyKey, any>>() {
return ThriftApi as unknown as new (...args: ThriftApiArgs) => {
[N in keyof T]: (
...args: Parameters<T[N]>
) => ReturnType<T[N]> extends Promise<infer R> ? Observable<R> : never;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type WrappedThriftApi<T extends Record<PropertyKey, any>> = new (...args: ThriftApiArgs) => {
[N in keyof T]: (
...args: Parameters<T[N]>
) => ReturnType<T[N]> extends Promise<infer R> ? Observable<R> : never;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function createThriftApi<T extends Record<PropertyKey, any>>(): WrappedThriftApi<T> {
return ThriftApi as never;
}

View File

@ -1,58 +1,88 @@
import { from } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { ConnectOptions } from '@vality/woody/src/connect-options';
import { KeycloakService } from 'keycloak-angular';
import pick from 'lodash-es/pick';
import { combineLatest, from } from 'rxjs';
import { first, map, shareReplay, switchMap } from 'rxjs/operators';
import { ThriftConnector } from '../thrift-connector';
import { createThriftInstance, thriftInstanceToObject } from '../thrift-instance';
import { KeycloakTokenInfoService } from '../../../shared/services';
import { ThriftAstMetadata } from '../thrift-instance';
import { ThriftApiArgs } from './types/thrift-api-args';
import {
callThriftServiceMethodWithConvert,
createAuthorizationHeaders,
createDeprecatedUserIdentityHeaders,
createUserIdentityHeaders,
createWachterHeaders,
ThriftClientMainOptions,
UserIdentityHeaderParams,
} from './utils';
export class ThriftApi extends ThriftConnector {
constructor(...[injector, options]: ThriftApiArgs) {
super(injector, options);
export class ThriftApi {
private connectOptions$ = combineLatest([
this.injector.get(KeycloakTokenInfoService).decoded$,
this.injector.get(KeycloakService).getToken(),
]).pipe(
map(([{ email, sub: id, preferred_username: username }, token]) =>
this.getConnectOptions({ email, id, username }, token)
),
shareReplay({ refCount: true, bufferSize: 1 })
);
private methodOptions$ = from(this.options.metadata()).pipe(
map((metadata) => ({
metadata: metadata as ThriftAstMetadata[],
namespaceName: this.options.name,
...pick(this.options, 'serviceName', 'context'),
})),
shareReplay({ refCount: true, bufferSize: 1 })
);
constructor(private injector: ThriftApiArgs[0], private options: ThriftApiArgs[1]) {
this.initServiceMethods();
}
private initServiceMethods() {
Object.assign(
this,
Object.fromEntries(
options.functions.map((methodName) => [
this.options.functions.map((methodName) => [
methodName,
(...methodArgs) =>
from(options.metadata()).pipe(
switchMap((metadata) =>
this.callThriftServiceMethodWithConvert(
options.name,
options.serviceName,
methodName,
methodArgs,
metadata,
options.context
)
)
),
this.createMethod(methodName),
])
)
);
}
private callThriftServiceMethodWithConvert(
namespaceName: string,
serviceName: string,
methodName: string,
methodArgs: any[],
metadata: any,
context: any
) {
const methodMetadata = metadata.find((m) => m.name === namespaceName).ast.service[
serviceName
].functions[methodName];
const methodThriftArgs = methodArgs.map((arg, idx) =>
createThriftInstance(
metadata,
context,
namespaceName,
methodMetadata.args[idx].type,
arg
)
);
return this.callThriftServiceMethod(methodName, ...methodThriftArgs).pipe(
map((v) => thriftInstanceToObject(metadata, namespaceName, methodMetadata.type, v))
);
private createMethod(methodName: string) {
return (...methodArgs) =>
combineLatest([this.connectOptions$, this.methodOptions$]).pipe(
first(),
switchMap(([connectOptions, methodOptions]) =>
callThriftServiceMethodWithConvert(
connectOptions,
methodOptions,
methodName,
methodArgs
)
)
);
}
private getConnectOptions(
userIdentityHeaderParams: Partial<UserIdentityHeaderParams>,
token: string
): ThriftClientMainOptions & ConnectOptions {
return {
...pick(this.options, 'hostname', 'port', 'service', 'deprecatedHeaders'),
path: this.options.wachterServiceName ? '/wachter' : this.options.path,
headers: Object.assign(
createUserIdentityHeaders(userIdentityHeaderParams),
this.options.deprecatedHeaders &&
createDeprecatedUserIdentityHeaders(userIdentityHeaderParams),
this.options.wachterServiceName && {
...createWachterHeaders(this.options.wachterServiceName),
...createAuthorizationHeaders(token),
}
),
};
}
}

View File

@ -1,12 +1,15 @@
export interface ThriftApiOptions {
import { Overwrite } from 'utility-types';
import { ThriftInstanceContext } from '../../thrift-instance';
import { ThriftClientMainOptions } from '../utils';
export interface ThriftApiOptions extends Overwrite<ThriftClientMainOptions, { path?: string }> {
name: string;
service: object;
serviceName: string;
path: string;
hostname?: string;
port?: string;
metadata: () => Promise<any>;
context: any;
// https://github.com/valitydev/wachter/blob/master/src/main/resources/application.yml
wachterServiceName?: string;
metadata: () => Promise<unknown>;
context: ThriftInstanceContext;
functions: string[];
deprecatedHeaders?: boolean;
}

View File

@ -0,0 +1,34 @@
import { ConnectOptions } from '@vality/woody/src/connect-options';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import {
createThriftInstance,
ThriftAstMetadata,
ThriftInstanceContext,
thriftInstanceToObject,
} from '../../thrift-instance';
import { callThriftServiceMethod, ThriftClientMainOptions } from './call-thrift-service-method';
interface ThriftServiceMethodOptions {
namespaceName: string;
serviceName: string;
metadata: ThriftAstMetadata[];
context: ThriftInstanceContext;
}
export function callThriftServiceMethodWithConvert<T>(
connectOptions: ThriftClientMainOptions & ConnectOptions,
{ namespaceName, serviceName, metadata, context }: ThriftServiceMethodOptions,
methodName: string,
methodArgs: unknown[]
): Observable<T> {
const methodMetadata = metadata.find((m) => m.name === namespaceName).ast.service[serviceName]
.functions[methodName];
const methodThriftArgs = methodArgs.map((arg, idx) =>
createThriftInstance(metadata, context, namespaceName, methodMetadata.args[idx].type, arg)
);
return callThriftServiceMethod<T>(connectOptions, methodName, methodThriftArgs).pipe(
map((v) => thriftInstanceToObject(metadata, namespaceName, methodMetadata.type, v))
);
}

View File

@ -0,0 +1,61 @@
import connectClient from '@vality/woody';
import { ConnectOptions } from '@vality/woody/src/connect-options';
import isNil from 'lodash-es/isNil';
import { Observable } from 'rxjs';
export interface ThriftClientMainOptions {
path: string;
service: object;
hostname?: string;
port?: string;
}
const DEFAULT_CONNECT_OPTIONS: ConnectOptions = {
deadlineConfig: {
amount: 3,
unitOfTime: 'm',
},
};
export function callThriftServiceMethod<T>(
{ hostname, port, path, service, ...options }: ThriftClientMainOptions & ConnectOptions,
serviceMethodName: string,
serviceMethodArgs: unknown[] = []
): Observable<T> {
return new Observable<T>((observer) => {
try {
/**
* Connection errors come with HTTP errors (!= 200) and should be handled with errors from the service.
* You need to have 1 free connection per request. Otherwise, the error cannot be caught or identified.
* TODO: Optimization option: add a connection pool.
*/
const connection = connectClient(
hostname ?? location.hostname,
port ?? location.port,
path,
service,
{ ...DEFAULT_CONNECT_OPTIONS, ...options },
(err) => {
observer.error(err);
observer.complete();
}
);
const serviceMethod = connection[serviceMethodName] as (...args: unknown[]) => unknown;
if (isNil(serviceMethod)) {
observer.error(
`Service method: "${serviceMethodName}" is not found in thrift client`
);
observer.complete();
} else {
serviceMethod.call(connection, ...serviceMethodArgs, (err, result: T) => {
if (err) observer.error(err);
else observer.next(result);
observer.complete();
});
}
} catch (err) {
observer.error(err);
observer.complete();
}
});
}

View File

@ -0,0 +1,29 @@
const createPrefixedHeaders = (params: Record<string, string>, prefix: string) =>
Object.fromEntries(Object.entries(params).map(([k, v]) => [prefix + k, v]));
export type UserIdentityHeaderParams = Record<'email' | 'username' | 'id' | 'realm', string>;
const DEFAULT_USER_IDENTITY_HEADER_PARAMS: Partial<UserIdentityHeaderParams> = {
realm: 'internal',
};
export const createUserIdentityHeaders = (params: Partial<UserIdentityHeaderParams>) =>
createPrefixedHeaders(
{ ...DEFAULT_USER_IDENTITY_HEADER_PARAMS, ...params },
'woody.meta.user-identity.'
);
export const createDeprecatedUserIdentityHeaders = (params: Partial<UserIdentityHeaderParams>) =>
createPrefixedHeaders(
{ ...DEFAULT_USER_IDENTITY_HEADER_PARAMS, ...params },
'x-rbk-meta-user-identity.'
);
export const createAuthorizationHeaders = (token: string) => ({
authorization: `Bearer ${token}`,
});
export const createWachterHeaders = (serviceName: string) => ({
// eslint-disable-next-line @typescript-eslint/naming-convention
Service: serviceName,
});

View File

@ -0,0 +1,3 @@
export * from './create-connect-options';
export * from './call-thrift-service-method';
export * from './call-thrift-service-method-with-convert';

View File

@ -1,3 +1,2 @@
export * from './create-thrift-api';
export * from './thrift-connector';
export * from './thrift-instance';

View File

@ -1 +0,0 @@
export * from './thrift-connector';

View File

@ -1,68 +0,0 @@
import connectClient from '@vality/woody';
import isNil from 'lodash-es/isNil';
import { Observable } from 'rxjs';
import { switchMap, first } from 'rxjs/operators';
import { KeycloakTokenInfoService } from '@cc/app/shared/services';
import { ThriftApiArgs } from '../create-thrift-api/types/thrift-api-args';
import { ThriftApiOptions } from '../create-thrift-api/types/thrift-api-options';
import { toConnectOptions } from './utils';
export class ThriftConnector {
keycloakTokenInfoService: KeycloakTokenInfoService;
options: ThriftApiOptions;
constructor(...[injector, options]: ThriftApiArgs) {
this.keycloakTokenInfoService = injector.get(KeycloakTokenInfoService);
this.options = options;
}
protected callThriftServiceMethod<T>(
serviceMethodName: string,
...args: unknown[]
): Observable<T> {
return this.keycloakTokenInfoService.decoded$.pipe(
first(),
switchMap(
(token) =>
new Observable<T>((observer) => {
try {
/**
* Connection errors come with HTTP errors (!= 200) and should be handled with errors from the service.
* You need to have 1 free connection per request. Otherwise, the error cannot be caught or identified.
* TODO: Optimization option: add a connection pool.
*/
const connection = connectClient(
this.options.hostname || location.hostname,
this.options.port || location.port,
this.options.path,
this.options.service,
toConnectOptions(token, this.options.deprecatedHeaders),
(err) => {
observer.error(err);
observer.complete();
}
);
const serviceMethod = connection[serviceMethodName];
if (isNil(serviceMethod)) {
observer.error(
`Service method: "${serviceMethodName}" is not found in thrift client`
);
observer.complete();
} else {
serviceMethod.bind(connection)(...args, (err, result) => {
if (err) observer.error(err);
else observer.next(result);
observer.complete();
});
}
} catch (err) {
observer.error(err);
observer.complete();
}
})
)
);
}
}

View File

@ -1 +0,0 @@
export * from './to-connect-options';

View File

@ -1,35 +0,0 @@
import { ConnectOptions } from '@vality/woody/src/connect-options';
import { KeycloakToken } from '@cc/app/shared/services';
const toDepricatedHeaders = (email: string, username: string, partyID: string, realm: string) => ({
'x-rbk-meta-user-identity.email': email,
'x-rbk-meta-user-identity.realm': realm,
'x-rbk-meta-user-identity.username': username,
'x-rbk-meta-user-identity.id': partyID,
});
const toHeaders = (email: string, username: string, partyID: string, realm: string) => ({
'woody.meta.user-identity.email': email,
'woody.meta.user-identity.realm': realm,
'woody.meta.user-identity.username': username,
'woody.meta.user-identity.id': partyID,
});
export const toConnectOptions = (
{ email, sub, preferred_username }: KeycloakToken,
deprecatedHeaders = false,
realm = 'internal'
): ConnectOptions => ({
headers: {
...toHeaders(email, preferred_username, sub, realm),
...(deprecatedHeaders
? toDepricatedHeaders(email, preferred_username, sub, realm)
: undefined),
},
deadlineConfig: {
amount: 3,
unitOfTime: 'm',
},
deprecatedHeaders,
});

View File

@ -22,7 +22,6 @@ import { ApiModelPipesModule, ThriftPipesModule } from '@cc/app/shared/pipes';
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
import { TableModule } from '@cc/components/table';
import { ClaimManagementService } from '../../thrift-services/damsel/claim-management.service';
import { CreateClaimDialogComponent } from './components/create-claim-dialog/create-claim-dialog.component';
import { SearchClaimsComponentRouting } from './search-claims-routing.module';
import { SearchClaimsComponent } from './search-claims.component';
@ -63,6 +62,6 @@ import { SearchTableComponent } from './search-table/search-table.component';
ClaimMailPipePipe,
CreateClaimDialogComponent,
],
providers: [SearchClaimsService, ClaimManagementService],
providers: [SearchClaimsService],
})
export class SearchClaimsModule {}

View File

@ -6,7 +6,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
import { BaseDialogSuperclass, BaseDialogModule, BaseDialogService } from '@vality/ng-core';
import { BaseDialogSuperclass, BaseDialogModule } from '@vality/ng-core';
import { from, BehaviorSubject, Observable } from 'rxjs';
import { InvoicingService } from '@cc/app/api/payment-processing';
@ -64,7 +64,6 @@ export class ChangeChargebackStatusDialogComponent
constructor(
injector: Injector,
private invoicingService: InvoicingService,
private baseDialogService: BaseDialogService,
private notificationService: NotificationService,
private errorService: ErrorService,
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService

View File

@ -1,88 +0,0 @@
import { Injectable, NgZone } from '@angular/core';
import {
Claim,
ClaimID,
ClaimSearchQuery,
ClaimSearchResponse,
Modification,
} from '@vality/domain-proto/lib/claim_management';
import {
ClaimSearchQuery as ClaimSearchQueryType,
Modification as ModificationType,
} from '@vality/domain-proto/lib/claim_management/gen-nodejs/claim_management_types';
import * as ClaimManagement from '@vality/domain-proto/lib/claim_management/gen-nodejs/ClaimManagement';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
/**
* @deprecated use api/ClaimManagement service
*/
export class ClaimManagementService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/cm', ClaimManagement);
}
createClaim = (partyID: string, changeset: Modification[]): Observable<Claim> =>
this.toObservableAction('CreateClaim')(partyID, changeset);
searchClaims = (query: ClaimSearchQuery): Observable<ClaimSearchResponse> =>
this.toObservableAction('SearchClaims')(new ClaimSearchQueryType(query));
getClaim = (partyID: string, claimID: ClaimID): Observable<Claim> =>
this.toObservableAction('GetClaim')(partyID, claimID);
acceptClaim = (partyID: string, claimID: ClaimID): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('AcceptClaim')(partyID, claimID, claim.revision)
)
);
requestClaimReview = (partyID: string, claimID: ClaimID): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('RequestClaimReview')(partyID, claimID, claim.revision)
)
);
requestClaimChanges = (partyID: string, claimID: ClaimID): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('RequestClaimChanges')(partyID, claimID, claim.revision)
)
);
denyClaim = (partyID: string, claimID: ClaimID, reason: string): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('DenyClaim')(partyID, claimID, claim.revision, reason)
)
);
revokeClaim = (partyID: string, claimID: ClaimID, reason: string): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('RevokeClaim')(partyID, claimID, claim.revision, reason)
)
);
updateClaim = (
partyID: string,
claimID: ClaimID,
changeset: Modification[]
): Observable<void> =>
this.getClaim(partyID, claimID).pipe(
switchMap((claim) =>
this.toObservableAction('UpdateClaim')(
claim.party_id,
claim.id,
claim.revision,
changeset.map((m) => new ModificationType(m))
)
)
);
}

View File

@ -1,13 +1,12 @@
import { NgModule } from '@angular/core';
import { ClaimManagementService } from './claim-management.service';
import { DomainStoreService } from './domain-store.service';
import { PaymentProcessingService } from './payment-processing.service';
import { RoutingRulesModule } from './routing-rules';
@NgModule({
imports: [RoutingRulesModule],
providers: [PaymentProcessingService, DomainStoreService, ClaimManagementService],
providers: [PaymentProcessingService, DomainStoreService],
})
/**
* @deprecated

View File

@ -16,6 +16,7 @@ import {
InvoicePaymentAdjustmentParams as InvoicePaymentAdjustmentParamsObject,
InvoiceRepairScenario as InvoiceRepairScenarioObject,
} from '@vality/domain-proto/lib/payment_processing/gen-nodejs/payment_processing_types';
import { KeycloakService } from 'keycloak-angular';
import { Observable, timer } from 'rxjs';
import { first, map, share, switchMap } from 'rxjs/operators';
@ -28,8 +29,18 @@ import { createDamselInstance, damselInstanceToObject } from './utils/create-dam
* @deprecated
*/
export class PaymentProcessingService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/processing/invoicing', Invoicing);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(
zone,
keycloakTokenInfoService,
keycloakService,
'/v1/processing/invoicing',
Invoicing
);
}
getPaymentAdjustment = (

View File

@ -1,6 +1,7 @@
import { Injectable, NgZone } from '@angular/core';
import { SearchHit } from '@vality/deanonimus-proto';
import * as Deanonimus from '@vality/deanonimus-proto/lib/deanonimus/gen-nodejs/Deanonimus';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
@ -8,8 +9,12 @@ import { ThriftService } from '../services/thrift/thrift-service';
@Injectable({ providedIn: 'root' })
export class DeanonimusService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/deanonimus', Deanonimus);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(zone, keycloakTokenInfoService, keycloakService, '/deanonimus', Deanonimus);
}
searchParty = (text: string): Observable<SearchHit[]> =>

View File

@ -9,6 +9,7 @@ import {
} from '@vality/file-storage-proto';
import { Timestamp } from '@vality/file-storage-proto/lib/base';
import * as FileStorage from '@vality/file-storage-proto/lib/file_storage/gen-nodejs/FileStorage';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
@ -16,8 +17,12 @@ import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
export class FileStorageService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/file_storage', FileStorage);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(zone, keycloakTokenInfoService, keycloakService, '/file_storage', FileStorage);
}
createNewFile = (metadata: Metadata, expiresAt: Timestamp): Observable<NewFileResult> =>

View File

@ -1,20 +0,0 @@
import { CategoryRef, ProviderObject } from '@vality/domain-proto/lib/domain';
import get from 'lodash-es/get';
export const filterProvidersByCategories = (
objects: ProviderObject[],
shopCategories: number[]
): ProviderObject[] =>
objects.filter((obj) => {
const predicate = (category: CategoryRef) =>
!!shopCategories.find((shopCategory) => shopCategory === category.id);
const paymentCats = get(obj, 'data.payment_terms.categories.value');
const recurrentCats = get(obj, 'data.recurrent_paytool_terms.categories.value');
if (paymentCats) {
return !!Array.from(paymentCats.values()).find(predicate);
}
if (recurrentCats) {
return !!Array.from(recurrentCats.values()).find(predicate);
}
return null;
});

View File

@ -1,14 +0,0 @@
import { ProviderObject } from '@vality/domain-proto/lib/domain';
import get from 'lodash-es/get';
export const filterProvidersByCategoryId = (
objects: ProviderObject[],
categoryId: number
): ProviderObject[] =>
objects.filter((obj) => {
const paymentCats = get(obj, 'data.payment_terms.categories.value', []);
const recurrentCats = get(obj, 'data.recurrent_paytool_terms.categories.value', []);
return !![...paymentCats, ...recurrentCats]
.map((c) => c.id)
.find((id) => id === categoryId);
});

View File

@ -1 +0,0 @@
export * from './filter-providers-by-category-id';

View File

@ -2,6 +2,7 @@ import { Injectable, NgZone } from '@angular/core';
import { DepositParams } from '@vality/fistful-proto/lib/fistful_admin';
import { DepositParams as DepositParamsObject } from '@vality/fistful-proto/lib/fistful_admin/gen-nodejs/fistful_admin_types';
import * as FistfulAdmin from '@vality/fistful-proto/lib/fistful_admin/gen-nodejs/FistfulAdmin';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
@ -9,8 +10,12 @@ import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
export class FistfulAdminService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/admin', FistfulAdmin);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(zone, keycloakTokenInfoService, keycloakService, '/v1/admin', FistfulAdmin);
}
createDeposit(params: DepositParams): Observable<void> {

View File

@ -2,6 +2,7 @@ import { Inject, Injectable, NgZone } from '@angular/core';
import { StatDeposit, StatRequest, StatResponse } from '@vality/fistful-proto/lib/fistful_stat';
import { StatRequest as ThriftStatRequest } from '@vality/fistful-proto/lib/fistful_stat/gen-nodejs/fistful_stat_types';
import * as FistfulStatistics from '@vality/fistful-proto/lib/fistful_stat/gen-nodejs/FistfulStatistics';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@ -21,9 +22,10 @@ export class FistfulStatisticsService extends ThriftService {
keycloakTokenInfoService: KeycloakTokenInfoService,
zone: NgZone,
@Inject(SEARCH_LIMIT) private searchLimit: number,
@Inject(SMALL_SEARCH_LIMIT) private smallSearchLimit: number
@Inject(SMALL_SEARCH_LIMIT) private smallSearchLimit: number,
keycloakService: KeycloakService
) {
super(zone, keycloakTokenInfoService, '/fistful/stat', FistfulStatistics);
super(zone, keycloakTokenInfoService, keycloakService, '/fistful/stat', FistfulStatistics);
}
getDeposits(

View File

@ -2,6 +2,7 @@ import { Injectable, NgZone } from '@angular/core';
import { RepairScenario, SessionID } from '@vality/fistful-proto/lib/withdrawal_session';
import * as Repairer from '@vality/fistful-proto/lib/withdrawal_session/gen-nodejs/Repairer';
import { RepairScenario as RepairScenarioObject } from '@vality/fistful-proto/lib/withdrawal_session/gen-nodejs/withdrawal_session_types';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
@ -9,8 +10,18 @@ import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
export class RepairerService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/repair/withdrawal/session', Repairer);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(
zone,
keycloakTokenInfoService,
keycloakService,
'/v1/repair/withdrawal/session',
Repairer
);
}
repair = (id: SessionID, scenario: RepairScenario): Observable<void> =>

View File

@ -1,5 +1,3 @@
export * from './filters';
export * from './utils/get-thrift-instance';
export * from './file-storage';
export * from './messages';
export * from './damsel';

View File

@ -6,6 +6,7 @@ import {
MachineDescriptor as MachineDescriptorObject,
Reference as ReferenceObject,
} from '@vality/machinegun-proto/lib/state_processing/gen-nodejs/state_processing_types';
import { KeycloakService } from 'keycloak-angular';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
@ -13,8 +14,12 @@ import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
export class AutomatonService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/automaton', Automaton);
constructor(
zone: NgZone,
keycloakTokenInfoService: KeycloakTokenInfoService,
keycloakService: KeycloakService
) {
super(zone, keycloakTokenInfoService, keycloakService, '/v1/automaton', Automaton);
}
simpleRepair = (ns: Namespace, ref: Reference): Observable<void> =>

View File

@ -1 +0,0 @@
export * from './messages.module';

View File

@ -1,8 +0,0 @@
import { NgModule } from '@angular/core';
import { MessagesService } from './messages.service';
@NgModule({
providers: [MessagesService],
})
export class MessagesModule {}

View File

@ -1,40 +0,0 @@
import { Injectable, NgZone } from '@angular/core';
import {
Conversation,
ConversationFilter,
ConversationId,
GetConversationResponse,
User,
} from '@vality/messages-proto';
import {
Conversation as ConversationType,
ConversationFilter as ConversationFilterType,
User as UserType,
} from '@vality/messages-proto/lib/messages/gen-nodejs/messages_types';
import * as MessageServiceClient from '@vality/messages-proto/lib/messages/gen-nodejs/MessageService';
import { Observable } from 'rxjs';
import { KeycloakTokenInfoService } from '../../keycloak-token-info.service';
import { ThriftService } from '../services/thrift/thrift-service';
@Injectable()
/**
* @deprecated
*/
export class MessagesService extends ThriftService {
constructor(zone: NgZone, keycloakTokenInfoService: KeycloakTokenInfoService) {
super(zone, keycloakTokenInfoService, '/v1/messages', MessageServiceClient);
}
getConversations = (
ids: ConversationId[],
filter: ConversationFilter
): Observable<GetConversationResponse> =>
this.toObservableAction('GetConversations')(ids, new ConversationFilterType(filter));
saveConversations = (conversations: Conversation[], user: User): Observable<void> =>
this.toObservableAction('SaveConversations')(
conversations.map((c) => new ConversationType(c)),
new UserType(user)
);
}

View File

@ -1,13 +0,0 @@
import { Conversation, ConversationStatus } from '@vality/messages-proto';
import * as moment from 'moment';
import * as uuid from 'uuid/v4';
export const createSingleMessageConversationParams = (
conversationId: string,
text: string,
userId: string
): Conversation => ({
conversation_id: conversationId,
messages: [{ message_id: uuid(), text, user_id: userId, timestamp: moment().toISOString() }],
status: ConversationStatus.ACTUAL,
});

View File

@ -1 +0,0 @@
export * from './create-single-message-conversation-params';

View File

@ -1,8 +1,13 @@
import { NgZone } from '@angular/core';
import connectClient from '@vality/woody';
import { Observable } from 'rxjs';
import { KeycloakService } from 'keycloak-angular';
import { Observable, from, switchMap } from 'rxjs';
import { timeout } from 'rxjs/operators';
import {
createWachterHeaders,
createAuthorizationHeaders,
} from '../../../api/utils/create-thrift-api/utils';
import { KeycloakTokenInfoService } from '../../../keycloak-token-info.service';
type Exception<N = string, T = any> = {
@ -18,8 +23,10 @@ export class ThriftService {
constructor(
private zone: NgZone,
private keycloakTokenInfoService: KeycloakTokenInfoService,
private keycloakService: KeycloakService,
endpoint: string,
thriftService: any
thriftService: any,
private wachterServiceName?: string
) {
this.endpoint = endpoint;
this.service = thriftService;
@ -30,27 +37,37 @@ export class ThriftService {
deprecatedHeaders = true
): T {
return ((...args) =>
new Observable<any>((observer) => {
const cb = (msg) => {
observer.error(msg);
observer.complete();
};
this.zone.run(() => {
try {
const client = this.createClient(cb, deprecatedHeaders);
client[name](...args, (ex: Exception, result) => {
if (ex) observer.error(ex);
else observer.next(result);
observer.complete();
});
} catch (e) {
cb(e);
}
});
}).pipe(timeout(60000 * 3))) as any;
from(this.keycloakService.getToken()).pipe(
switchMap(
(token) =>
new Observable<any>((observer) => {
const cb = (msg) => {
observer.error(msg);
observer.complete();
};
this.zone.run(() => {
try {
const client = this.createClient(cb, deprecatedHeaders, token);
client[name](...args, (ex: Exception, result) => {
if (ex) observer.error(ex);
else observer.next(result);
observer.complete();
});
} catch (e) {
cb(e);
}
});
})
),
timeout(60000 * 3)
)) as any;
}
private createClient(errorCb: (cb: () => void) => void, deprecatedHeaders: boolean) {
private createClient(
errorCb: (cb: () => void) => void,
deprecatedHeaders: boolean,
token: string
) {
const { email, preferred_username, sub } = this.keycloakTokenInfoService.decodedUserToken;
return connectClient(
location.hostname,
@ -71,6 +88,12 @@ export class ThriftService {
'x-rbk-meta-user-identity.id': sub,
}
: undefined),
...(this.wachterServiceName
? {
...createWachterHeaders(this.wachterServiceName),
...createAuthorizationHeaders(token),
}
: {}),
},
deadlineConfig: {
amount: 3,