mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 23:40:56 +00:00
fix: fitler out the client side request
This commit is contained in:
@@ -3,6 +3,8 @@ import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { AuditLogCommand } from "@tria-plc/auditlog";
|
||||
|
||||
import { CLIENT_APP_HEADER } from "../auth/login-audience.middleware";
|
||||
|
||||
export interface AuditLogListResult {
|
||||
count: number;
|
||||
items: AuditLogCommand[];
|
||||
@@ -38,6 +40,15 @@ export class AuditService {
|
||||
"(audit_log_commands.auditLogId IS NULL OR auditLog.status = :status)",
|
||||
{ status: "Commit" },
|
||||
)
|
||||
// Backoffice-only view: portal (customer-facing) writes carry the same
|
||||
// request-header set by every axios call from that app — see
|
||||
// login-audience.middleware.ts. Rows with no linked auditLog (child/
|
||||
// event commands with no request context) stay visible; they aren't
|
||||
// attributable to any frontend, so they're not portal noise either.
|
||||
.andWhere(
|
||||
"(audit_log_commands.auditLogId IS NULL OR auditLog.requestHeader ->> :clientAppHeader = :clientApp)",
|
||||
{ clientAppHeader: CLIENT_APP_HEADER, clientApp: "backoffice" },
|
||||
)
|
||||
.select([
|
||||
"audit_log_commands.id",
|
||||
"audit_log_commands.createdAt",
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
AuditLogRow,
|
||||
AuditQueryMethod,
|
||||
AuditUser,
|
||||
LocalizedText,
|
||||
} from "@/services/audit.service";
|
||||
import {
|
||||
DataTable,
|
||||
@@ -44,18 +45,20 @@ function formatDateTime(iso: string): string {
|
||||
});
|
||||
}
|
||||
|
||||
// The producer (@tria-plc/auditlog's ClientLoggerInterceptor) builds
|
||||
// `name` from `${auditUser?.firstName} ${auditUser?.lastName}` — this app's
|
||||
// user model only has a single `name` field, and unauthenticated/customer
|
||||
// flows (e.g. Fayda verification) have no auditUser at all, so this literal
|
||||
// "undefined undefined" ends up stored as-is. Filter it back out on render
|
||||
// rather than showing raw garbage.
|
||||
// See LocalizedText: `name`/`title` lifted from a raw audited entity can be
|
||||
// a plain string or IAM's { am, en } — never render either directly.
|
||||
// "undefined undefined" is the producer's own broken template when no user
|
||||
// was attached at all (unauthenticated/customer flows, e.g. Fayda
|
||||
// verification) — filtered out here rather than shown as raw garbage.
|
||||
function localize(value: LocalizedText | null | undefined): string | undefined {
|
||||
if (!value) return undefined;
|
||||
if (typeof value === "object") return value.en ?? value.am ?? undefined;
|
||||
if (/^undefined(\s+undefined)?$/.test(value.trim())) return undefined;
|
||||
return value;
|
||||
}
|
||||
|
||||
function formatUser(user: AuditUser | null | undefined): string {
|
||||
const name = user?.name;
|
||||
if (typeof name === "string" && /^undefined(\s+undefined)?$/.test(name.trim())) {
|
||||
return "—";
|
||||
}
|
||||
return name ?? user?.id ?? "—";
|
||||
return localize(user?.name) ?? user?.id ?? "—";
|
||||
}
|
||||
|
||||
function summarize(row: AuditLogRow): string {
|
||||
@@ -66,7 +69,9 @@ function summarize(row: AuditLogRow): string {
|
||||
.join(", ") + (row.changes.length > 2 ? `, +${row.changes.length - 2} more` : "");
|
||||
}
|
||||
if (row.payload) {
|
||||
return row.payload.name ?? row.payload.title ?? row.payload.id ?? "—";
|
||||
return (
|
||||
localize(row.payload.name) ?? localize(row.payload.title) ?? row.payload.id ?? "—"
|
||||
);
|
||||
}
|
||||
return "—";
|
||||
}
|
||||
|
||||
@@ -19,9 +19,18 @@ export interface AuditFieldChange {
|
||||
to: unknown;
|
||||
}
|
||||
|
||||
// IAM entities (users, orgs, positions, ...) name themselves bilingually —
|
||||
// see edr-org.seeder.ts. Any `name`/`title` field lifted from a raw audited
|
||||
// entity (auditLog.user, payload) can come back as either a plain string or
|
||||
// this shape; both `name` fields below reflect that.
|
||||
export type LocalizedText = string | { am?: string; en?: string };
|
||||
|
||||
// The vendored interceptor's own broken template produces a plain string
|
||||
// ("undefined undefined") when no user was attached at all (unauthenticated/
|
||||
// customer flows) — that's the non-bilingual string case for `name` here.
|
||||
export interface AuditUser {
|
||||
id?: string;
|
||||
name?: string;
|
||||
name?: LocalizedText;
|
||||
organizationId?: string;
|
||||
organizationName?: string;
|
||||
[key: string]: unknown;
|
||||
@@ -34,7 +43,7 @@ export interface AuditLogRow {
|
||||
entityName: string;
|
||||
queryMethod: AuditQueryMethod;
|
||||
changes?: AuditFieldChange[] | null;
|
||||
payload?: { name?: string; title?: string; id?: string } | null;
|
||||
payload?: { name?: LocalizedText; title?: LocalizedText; id?: string } | null;
|
||||
auditLog?: { id?: string; user?: AuditUser | null };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user