2026-06-16 15:59:53 -05:00
|
|
|
import { authApi, handleApiError } from "@/main-axios";
|
|
|
|
|
|
2026-08-19 14:12:06 -05:00
|
|
|
export type AuditLog = {
|
2026-06-16 15:59:53 -05:00
|
|
|
id: number;
|
|
|
|
|
userId: string;
|
|
|
|
|
username: string;
|
|
|
|
|
action: string;
|
|
|
|
|
resourceType: string;
|
|
|
|
|
resourceId: string | null;
|
|
|
|
|
resourceName: string | null;
|
|
|
|
|
details: string | null;
|
|
|
|
|
ipAddress: string | null;
|
|
|
|
|
userAgent: string | null;
|
|
|
|
|
success: boolean;
|
|
|
|
|
errorMessage: string | null;
|
|
|
|
|
timestamp: string;
|
2026-08-19 14:12:06 -05:00
|
|
|
};
|
2026-06-16 15:59:53 -05:00
|
|
|
|
|
|
|
|
export interface AuditLogFilters {
|
|
|
|
|
page?: number;
|
|
|
|
|
limit?: number;
|
|
|
|
|
userId?: string;
|
|
|
|
|
action?: string;
|
|
|
|
|
resourceType?: string;
|
|
|
|
|
success?: boolean | "";
|
|
|
|
|
startDate?: string;
|
|
|
|
|
endDate?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AuditLogResponse {
|
|
|
|
|
logs: AuditLog[];
|
|
|
|
|
total: number;
|
|
|
|
|
page: number;
|
|
|
|
|
totalPages: number;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-19 12:29:52 -05:00
|
|
|
function stringValue(value: unknown, fallback = ""): string {
|
|
|
|
|
return typeof value === "string" ? value : fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function numberValue(value: unknown, fallback = 0): number {
|
|
|
|
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function nullableStringValue(value: unknown): string | null {
|
|
|
|
|
return typeof value === "string" && value ? value : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function boolValue(value: unknown): boolean {
|
|
|
|
|
return value === true || value === 1 || value === "1";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function mapAuditLog(row: Record<string, unknown>): AuditLog {
|
|
|
|
|
return {
|
|
|
|
|
id: numberValue(row.id),
|
|
|
|
|
userId: stringValue(row.userId ?? row.user_id),
|
|
|
|
|
username: stringValue(row.username),
|
|
|
|
|
action: stringValue(row.action, "unknown"),
|
|
|
|
|
resourceType: stringValue(row.resourceType ?? row.resource_type, "unknown"),
|
|
|
|
|
resourceId: nullableStringValue(row.resourceId ?? row.resource_id),
|
|
|
|
|
resourceName: nullableStringValue(row.resourceName ?? row.resource_name),
|
|
|
|
|
details: nullableStringValue(row.details),
|
|
|
|
|
ipAddress: nullableStringValue(row.ipAddress ?? row.ip_address),
|
|
|
|
|
userAgent: nullableStringValue(row.userAgent ?? row.user_agent),
|
|
|
|
|
success: boolValue(row.success),
|
|
|
|
|
errorMessage: nullableStringValue(row.errorMessage ?? row.error_message),
|
|
|
|
|
timestamp: stringValue(row.timestamp, new Date(0).toISOString()),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 15:59:53 -05:00
|
|
|
export async function getAuditLogs(
|
|
|
|
|
filters: AuditLogFilters = {},
|
|
|
|
|
): Promise<AuditLogResponse> {
|
|
|
|
|
try {
|
|
|
|
|
const params = new URLSearchParams();
|
|
|
|
|
if (filters.page) params.set("page", String(filters.page));
|
|
|
|
|
if (filters.limit) params.set("limit", String(filters.limit));
|
|
|
|
|
if (filters.userId) params.set("userId", filters.userId);
|
|
|
|
|
if (filters.action) params.set("action", filters.action);
|
|
|
|
|
if (filters.resourceType) params.set("resourceType", filters.resourceType);
|
|
|
|
|
if (filters.success !== undefined && filters.success !== "")
|
|
|
|
|
params.set("success", String(filters.success));
|
|
|
|
|
if (filters.startDate) params.set("startDate", filters.startDate);
|
|
|
|
|
if (filters.endDate) params.set("endDate", filters.endDate);
|
|
|
|
|
|
|
|
|
|
const response = await authApi.get(`/audit-logs?${params.toString()}`);
|
2026-07-19 12:29:52 -05:00
|
|
|
const data = response.data as Partial<AuditLogResponse>;
|
|
|
|
|
const rows = Array.isArray(data.logs) ? data.logs : [];
|
|
|
|
|
return {
|
|
|
|
|
logs: rows.map((row) => mapAuditLog(row as Record<string, unknown>)),
|
|
|
|
|
total: numberValue(data.total),
|
|
|
|
|
page: numberValue(data.page, filters.page ?? 1),
|
|
|
|
|
totalPages: numberValue(data.totalPages, 1),
|
|
|
|
|
};
|
2026-06-16 15:59:53 -05:00
|
|
|
} catch (error) {
|
|
|
|
|
handleApiError(error, "fetch audit logs");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getAuditLogActions(): Promise<{ actions: string[] }> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await authApi.get("/audit-logs/actions");
|
|
|
|
|
return response.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
handleApiError(error, "fetch audit log actions");
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-20 14:56:39 -05:00
|
|
|
|
|
|
|
|
export interface AuditForwardingSettings {
|
|
|
|
|
url: string;
|
|
|
|
|
hasToken: boolean;
|
|
|
|
|
envConfigured: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getAuditForwarding(): Promise<AuditForwardingSettings> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await authApi.get("/users/audit-forwarding");
|
|
|
|
|
return response.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw handleApiError(error, "get audit forwarding settings");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function updateAuditForwarding(
|
|
|
|
|
url: string,
|
|
|
|
|
token?: string,
|
|
|
|
|
): Promise<{ url: string; hasToken: boolean }> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await authApi.patch("/users/audit-forwarding", {
|
|
|
|
|
url,
|
|
|
|
|
token,
|
|
|
|
|
});
|
|
|
|
|
return response.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw handleApiError(error, "update audit forwarding settings");
|
|
|
|
|
}
|
|
|
|
|
}
|