chore: strengthen backend eslint profile

This commit is contained in:
2026-09-28 11:04:18 +03:00
parent ca5dbcb382
commit 9b3558f96c
179 changed files with 4485 additions and 2716 deletions
@@ -1,24 +1,24 @@
import { Injectable } from '@nestjs/common';
import { BankCard, Prisma } from '../../../../../generated/prisma/client';
import { PrismaService } from '../../../../prisma/prisma.service';
import { bankBalance } from '../domain/bank-card.calculations';
import { rubMoney } from '../domain/rub-money';
import { BankCardsRepository } from '../infrastructure/bank-cards.repository';
import {
BankCardDto,
CreateBankCardDto,
UpdateBankCardDto,
} from '../presentation/bank-card.dto';
import { bankBalance } from '../domain/bank-card.calculations';
import { rubMoney } from '../domain/rub-money';
import {
cardInput,
BankErrorCode,
cardInput,
conflict,
currentDate,
fail,
fingerprint,
missing,
} from './bank-card-input';
import { BankCardsRepository } from '../infrastructure/bank-cards.repository';
type Tx = Prisma.TransactionClient;
@Injectable()
export class BankCardsService {
@@ -26,6 +26,7 @@ export class BankCardsService {
private readonly prisma: PrismaService,
private readonly repository: BankCardsRepository,
) {}
private async cardView(tx: Tx, card: BankCard): Promise<BankCardDto> {
const rows = await tx.bankCardOperation.findMany({
where: {
@@ -47,6 +48,7 @@ export class BankCardsService {
archivedAt: card.archivedAt?.toISOString() ?? null,
};
}
list(userId: string, includeArchived = false) {
return this.prisma.$transaction(async (tx) =>
Promise.all(
@@ -59,11 +61,13 @@ export class BankCardsService {
),
);
}
get(userId: string, id: string) {
return this.prisma.$transaction(async (tx) =>
this.cardView(tx, await this.repository.card(tx, userId, id)),
);
}
createCard(userId: string, dto: CreateBankCardDto) {
const input = cardInput(dto),
hash = fingerprint(input);
@@ -71,8 +75,10 @@ export class BankCardsService {
const existing = await tx.bankCard.findUnique({ where: { id: dto.id } });
if (existing) {
if (existing.userId !== userId) missing();
if (existing.createFingerprint !== hash)
// eslint-disable-next-line security/detect-possible-timing-attacks -- This compares an idempotency fingerprint after ownership validation, not a secret.
if (existing.createFingerprint !== hash) {
conflict(BankErrorCode.IntentConflict);
}
return this.cardView(tx, existing);
}
currentDate(input.openingDate);
@@ -85,6 +91,7 @@ export class BankCardsService {
);
});
}
updateCard(userId: string, id: string, dto: UpdateBankCardDto) {
return this.repository.write(async (tx) => {
const previous = await this.repository.card(tx, userId, id);
@@ -93,17 +100,17 @@ export class BankCardsService {
id,
name: dto.name ?? previous.name,
bankName:
dto.bankName === undefined
? (previous.bankName ?? undefined)
: (dto.bankName ?? undefined),
dto.bankName === undefined ?
(previous.bankName ?? undefined) :
(dto.bankName ?? undefined),
lastFour:
dto.lastFour === undefined
? (previous.lastFour ?? undefined)
: (dto.lastFour ?? undefined),
dto.lastFour === undefined ?
(previous.lastFour ?? undefined) :
(dto.lastFour ?? undefined),
paymentSystem:
dto.paymentSystem === undefined
? previous.paymentSystem
: dto.paymentSystem,
dto.paymentSystem === undefined ?
previous.paymentSystem :
dto.paymentSystem,
openingBalance:
dto.openingBalance ?? rubMoney(previous.openingBalanceKopecks),
openingDate: dto.openingDate ?? previous.openingDate,
@@ -111,8 +118,9 @@ export class BankCardsService {
const financial =
input.openingBalanceKopecks !== previous.openingBalanceKopecks ||
input.openingDate !== previous.openingDate;
if (financial && previous.archivedAt)
if (financial && previous.archivedAt) {
conflict(BankErrorCode.CardArchived);
}
currentDate(input.openingDate);
if (
await tx.bankCardOperation.findFirst({
@@ -123,20 +131,21 @@ export class BankCardsService {
OR: [{ cardId: id }, { targetCardId: id }],
},
})
)
) {
fail(BankErrorCode.OpeningDateConflict);
}
const changed = await tx.bankCard.updateMany({
where: { id, userId, version: dto.version },
data: {
...input,
paymentSystem: input.paymentSystem ?? null,
version: { increment: 1 },
...(dto.archived === undefined
? {}
: {
archivedAt: dto.archived
? (previous.archivedAt ?? new Date())
: null,
...(dto.archived === undefined ?
{} :
{
archivedAt: dto.archived ?
(previous.archivedAt ?? new Date()) :
null,
}),
},
});