79 lines
2.1 KiB
TypeScript
79 lines
2.1 KiB
TypeScript
const FIELD_LABELS: Record<string, string> = {
|
|
title: 'عنوان',
|
|
name: 'نام',
|
|
firstName: 'نام',
|
|
lastName: 'نام خانوادگی',
|
|
fullName: 'نام',
|
|
description: 'توضیحات',
|
|
body: 'متن',
|
|
mobile: 'موبایل',
|
|
phone: 'تلفن',
|
|
email: 'ایمیل',
|
|
status: 'وضعیت',
|
|
stageId: 'مرحله',
|
|
priority: 'اولویت',
|
|
dueAt: 'موعد',
|
|
amount: 'مبلغ',
|
|
subject: 'موضوع',
|
|
type: 'نوع',
|
|
city: 'شهر',
|
|
address: 'آدرس',
|
|
notes: 'یادداشت',
|
|
contactName: 'نام مخاطب',
|
|
};
|
|
|
|
const SECRET = /password|token|secret|otp|pin/i;
|
|
|
|
function textOf(value: unknown) {
|
|
if (typeof value === 'string') return value.trim().replace(/\s+/g, ' ');
|
|
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
return '';
|
|
}
|
|
|
|
function labelOf(source: unknown) {
|
|
if (!source || typeof source !== 'object' || Array.isArray(source)) return '';
|
|
const body = source as Record<string, unknown>;
|
|
const person = [textOf(body.firstName), textOf(body.lastName)].filter(Boolean).join(' ');
|
|
return (
|
|
person ||
|
|
textOf(body.title) ||
|
|
textOf(body.name) ||
|
|
textOf(body.subject) ||
|
|
textOf(body.fullName)
|
|
).slice(0, 120);
|
|
}
|
|
|
|
function changesOf(source: unknown) {
|
|
if (!source || typeof source !== 'object' || Array.isArray(source)) return '';
|
|
const bits: string[] = [];
|
|
for (const [key, value] of Object.entries(source as Record<string, unknown>)) {
|
|
if (SECRET.test(key)) continue;
|
|
const name = FIELD_LABELS[key];
|
|
if (!name) continue;
|
|
if (key.endsWith('Id')) {
|
|
bits.push(name);
|
|
} else {
|
|
const text = textOf(value).slice(0, 40);
|
|
if (!text) continue;
|
|
bits.push(`${name}: ${text}`);
|
|
}
|
|
if (bits.length >= 4) break;
|
|
}
|
|
return bits.join('، ');
|
|
}
|
|
|
|
export function auditStory(
|
|
method: string,
|
|
requestBody: unknown,
|
|
responseBody: unknown,
|
|
) {
|
|
const label = labelOf(responseBody) || labelOf(requestBody);
|
|
const detail = method === 'DELETE' ? '' : changesOf(requestBody);
|
|
const summary = [label, detail].filter(Boolean).join(' — ').slice(0, 500);
|
|
return {
|
|
label,
|
|
detail: detail.slice(0, 240),
|
|
summary,
|
|
};
|
|
}
|