refactor(tbank): centralize access rules
This commit is contained in:
@@ -1,14 +1,6 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import { RequestContextService } from '../common/logging/request-context.service';
|
||||
import { Environment } from '../config/env.validation';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import {
|
||||
BrokerageOperationsPageDto,
|
||||
BrokerageOperationsQueryDto,
|
||||
@@ -17,21 +9,14 @@ import {
|
||||
mapBrokerageOperation,
|
||||
operationCategory,
|
||||
} from './brokerage-operation.mapper';
|
||||
import { TbankAccessService } from './tbank-access.service';
|
||||
import { TbankClient } from './tbank.client';
|
||||
import { TbankCrypto } from './tbank.crypto';
|
||||
|
||||
const freshForMs = 30_000;
|
||||
const maxCachedPages = 100;
|
||||
const supportedAccounts = new Set([
|
||||
'ACCOUNT_TYPE_TINKOFF',
|
||||
'ACCOUNT_TYPE_TINKOFF_IIS',
|
||||
'ACCOUNT_TYPE_INVEST_BOX',
|
||||
'ACCOUNT_TYPE_INVEST_FUND',
|
||||
]);
|
||||
|
||||
@Injectable()
|
||||
export class BrokerageOperationsService {
|
||||
private readonly crypto: TbankCrypto;
|
||||
private readonly pages = new LRUCache<string, BrokerageOperationsPageDto>({
|
||||
max: maxCachedPages,
|
||||
ttl: freshForMs,
|
||||
@@ -39,15 +24,10 @@ export class BrokerageOperationsService {
|
||||
});
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
config: ConfigService<Environment, true>,
|
||||
private readonly access: TbankAccessService,
|
||||
private readonly tbank: TbankClient,
|
||||
private readonly requestContext: RequestContextService,
|
||||
) {
|
||||
this.crypto = TbankCrypto.fromBase64(
|
||||
config.getOrThrow('TOKEN_ENCRYPTION_KEY'),
|
||||
);
|
||||
}
|
||||
) {}
|
||||
|
||||
async get(
|
||||
userId: string,
|
||||
@@ -57,22 +37,7 @@ export class BrokerageOperationsService {
|
||||
this.requestContext.set({ userId, brokerageAccountId: accountId });
|
||||
const range = this.range(query);
|
||||
|
||||
try {
|
||||
const connection = await this.prisma.tbankConnection.findUnique({
|
||||
where: { userId },
|
||||
});
|
||||
if (!connection)
|
||||
throw new ConflictException({ code: 'TBANK_NOT_CONNECTED' });
|
||||
const token = this.crypto.decrypt(connection.encryptedToken);
|
||||
const accounts = await this.tbank.getOpenAccounts(token);
|
||||
if (
|
||||
!accounts.some(
|
||||
(account) =>
|
||||
account.id === accountId && supportedAccounts.has(account.type),
|
||||
)
|
||||
)
|
||||
throw new NotFoundException();
|
||||
|
||||
return this.access.withAccount(userId, accountId, async ({ token }) => {
|
||||
const key = cacheKey(userId, accountId, query, range);
|
||||
const cached = this.pages.get(key);
|
||||
if (cached) return cached;
|
||||
@@ -106,11 +71,7 @@ export class BrokerageOperationsService {
|
||||
};
|
||||
this.pages.set(key, page);
|
||||
return page;
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message === 'INVALID_TBANK_TOKEN')
|
||||
throw new BadRequestException({ code: 'INVALID_TBANK_TOKEN' });
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private range(query: BrokerageOperationsQueryDto) {
|
||||
|
||||
Reference in New Issue
Block a user