Update passport.client.ts
This commit is contained in:
parent
d1097a5089
commit
701dfbe2f5
@ -1,9 +1,21 @@
|
||||
import { BadGatewayException, BadRequestException, ConflictException, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
||||
import { BadGatewayException, BadRequestException, ConflictException, HttpException, HttpStatus, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
||||
import { createHash } from 'crypto';
|
||||
import { config } from '../../config';
|
||||
|
||||
// Ответ /api/v1/*: { result } или { errors: [{ code, input_field, description }] }.
|
||||
type V1Response<T> = { result?: T; errors?: { code: number; input_field?: string | null; description?: string | null }[] };
|
||||
// description — фраза паспорта на нескольких языках: { ru, en } (App\\Language\\Phrase), иногда строка.
|
||||
type V1Description = string | { ru?: string; en?: string } | null;
|
||||
type V1Response<T> = { result?: T; errors?: { code: number; input_field?: string | null; description?: V1Description }[] };
|
||||
|
||||
function describe(d: V1Description | undefined): string | null {
|
||||
if (!d) return null;
|
||||
if (typeof d === 'string') return d.trim() || null;
|
||||
return d.ru?.trim() || d.en?.trim() || null;
|
||||
}
|
||||
|
||||
// Коды 1002–1007 — не ошибка человека, а неверная настройка связи с паспортом:
|
||||
// нет метода, неверная подпись, нет платформы (config/api_v1_errors.php паспорта).
|
||||
const SETUP_CODES = new Set([1002, 1003, 1004, 1005, 1006, 1007]);
|
||||
|
||||
export type PassportUserFull = {
|
||||
uuid: string;
|
||||
@ -39,13 +51,15 @@ export type PassportPerson = {
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
export class PassportApiError extends Error {
|
||||
// Ошибка паспорта, которую код не превратил во что-то понятнее (humanize): отдаём 502 с текстом паспорта,
|
||||
// а не 500 «Internal server error».
|
||||
export class PassportApiError extends HttpException {
|
||||
constructor(
|
||||
readonly code: number,
|
||||
readonly field: string | null,
|
||||
message: string,
|
||||
) {
|
||||
super(message);
|
||||
super(message, HttpStatus.BAD_GATEWAY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,8 +132,13 @@ export class PassportClient {
|
||||
const r = data as V1Response<T>;
|
||||
if (r?.errors?.length) {
|
||||
const e = r.errors[0];
|
||||
this.logger.warn(`Паспорт ${method}: ошибка ${e.code} ${e.input_field ?? ''} ${e.description ?? ''}`);
|
||||
throw new PassportApiError(e.code, e.input_field ?? null, e.description || `Ошибка паспорта ${e.code}`);
|
||||
const text = describe(e.description) || `Ошибка паспорта ${e.code}`;
|
||||
if (SETUP_CODES.has(e.code)) {
|
||||
this.logger.error(`Паспорт ${method}: ${text} (код ${e.code}) — проверьте PASSPORT_URL, PLATFORM_CODE, PASSPORT_PLATFORM_TOKEN и что метод выложен`);
|
||||
throw new PassportApiError(e.code, null, `Паспорт Aspans не настроен для «Обходов»: ${text} (код ${e.code})`);
|
||||
}
|
||||
this.logger.warn(`Паспорт ${method}: ошибка ${e.code}${e.input_field ? ` [${e.input_field}]` : ''} ${text}`);
|
||||
throw new PassportApiError(e.code, e.input_field ?? null, text);
|
||||
}
|
||||
if (!r || !('result' in r)) throw new BadGatewayException('Паспорт Aspans ответил без результата');
|
||||
return r.result as T;
|
||||
@ -224,7 +243,7 @@ export class PassportClient {
|
||||
}
|
||||
|
||||
private humanize(e: unknown) {
|
||||
if (!(e instanceof PassportApiError)) return e;
|
||||
if (!(e instanceof PassportApiError) || SETUP_CODES.has(e.code)) return e;
|
||||
if (e.field === 'email' && /разным/.test(e.message)) {
|
||||
return new ConflictException('Этот email и этот телефон принадлежат разным людям в Aspans ID');
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user