Replace bare console.error() calls with logError() utility across all 47 API route handlers. logError() prints timestamp + context + message + stack trace + extra request data to stderr, and redacts sensitive fields (password, token, secret, key, etc.) from logged objects.
129 lines
4.6 KiB
TypeScript
129 lines
4.6 KiB
TypeScript
import { logError } from "@/lib/logger";
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
import { query } from "@/lib/db";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
interface AuditLog {
|
|
source: "user_activity" | "project_audit";
|
|
id: number;
|
|
actor_uid: string | null;
|
|
action: string;
|
|
resource: string | null;
|
|
ip_address: string | null;
|
|
user_agent: string | null;
|
|
created_at: string;
|
|
}
|
|
|
|
export async function GET(req: NextRequest) {
|
|
try {
|
|
const { searchParams } = req.nextUrl;
|
|
const page = Math.max(1, parseInt(searchParams.get("page") || "1", 10));
|
|
const pageSize = Math.max(1, parseInt(searchParams.get("pageSize") || "20", 10));
|
|
const source = searchParams.get("source") || "all";
|
|
const action = searchParams.get("action") || "";
|
|
const offset = (page - 1) * pageSize;
|
|
|
|
const actionPattern = action ? `%${action}%` : null;
|
|
const limitOffsetParams: unknown[] = [pageSize, offset];
|
|
|
|
let userQuery = "";
|
|
let projectQuery = "";
|
|
let userParams: unknown[] = [];
|
|
let projectParams: unknown[] = [];
|
|
|
|
// Build user_activity_log query
|
|
if (source !== "project") {
|
|
if (action) {
|
|
userParams = [actionPattern, ...limitOffsetParams];
|
|
userQuery = `SELECT 'user_activity' as source, id,
|
|
COALESCE(user_uid::text, '') as actor_uid,
|
|
action, NULL::text as resource,
|
|
ip_address, user_agent, created_at::text as created_at
|
|
FROM user_activity_log
|
|
WHERE action ILIKE $1
|
|
ORDER BY created_at DESC
|
|
LIMIT $2 OFFSET $3`;
|
|
} else {
|
|
userParams = limitOffsetParams;
|
|
userQuery = `SELECT 'user_activity' as source, id,
|
|
COALESCE(user_uid::text, '') as actor_uid,
|
|
action, NULL::text as resource,
|
|
ip_address, user_agent, created_at::text as created_at
|
|
FROM user_activity_log
|
|
ORDER BY created_at DESC
|
|
LIMIT $1 OFFSET $2`;
|
|
}
|
|
}
|
|
|
|
// Build project_audit_log query
|
|
if (source !== "user") {
|
|
if (action) {
|
|
projectParams = [actionPattern, ...limitOffsetParams];
|
|
projectQuery = `SELECT 'project_audit' as source, id,
|
|
COALESCE(actor::text, '') as actor_uid,
|
|
action, details as resource, ip_address,
|
|
NULL as user_agent, created_at::text as created_at
|
|
FROM project_audit_log
|
|
WHERE action ILIKE $1
|
|
ORDER BY created_at DESC
|
|
LIMIT $2 OFFSET $3`;
|
|
} else {
|
|
projectParams = limitOffsetParams;
|
|
projectQuery = `SELECT 'project_audit' as source, id,
|
|
COALESCE(actor::text, '') as actor_uid,
|
|
action, details as resource, ip_address,
|
|
NULL as user_agent, created_at::text as created_at
|
|
FROM project_audit_log
|
|
ORDER BY created_at DESC
|
|
LIMIT $1 OFFSET $2`;
|
|
}
|
|
}
|
|
|
|
const [userLogs, projectLogs] = await Promise.all([
|
|
userQuery ? query<AuditLog>(userQuery, userParams) : Promise.resolve({ rows: [] as AuditLog[] }),
|
|
projectQuery ? query<AuditLog>(projectQuery, projectParams) : Promise.resolve({ rows: [] as AuditLog[] }),
|
|
]);
|
|
|
|
// 合并并排序
|
|
const combined = [...userLogs.rows, ...projectLogs.rows].sort(
|
|
(a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
);
|
|
|
|
// 总数
|
|
const [userCountRes, projectCountRes] = await Promise.all([
|
|
userCountQuery(userParams, action),
|
|
projectCountQuery(projectParams, action),
|
|
]);
|
|
const total = parseInt(String(userCountRes.rows[0]?.count || "0"), 10) +
|
|
parseInt(String(projectCountRes.rows[0]?.count || "0"), 10);
|
|
|
|
return NextResponse.json({ logs: combined.slice(0, pageSize), total, page, pageSize });
|
|
} catch (e) {
|
|
logError("Platform audit logs error:", e);
|
|
return NextResponse.json({ error: "服务器错误" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
async function userCountQuery(params: unknown[], action: string | null) {
|
|
if (!params.length) return { rows: [] as { count: string }[] };
|
|
if (action) {
|
|
return query<{ count: string }>(
|
|
`SELECT COUNT(*) FROM user_activity_log WHERE action ILIKE $1`,
|
|
[params[0]]
|
|
);
|
|
}
|
|
return query<{ count: string }>(`SELECT COUNT(*) FROM user_activity_log`);
|
|
}
|
|
|
|
async function projectCountQuery(params: unknown[], action: string | null) {
|
|
if (!params.length) return { rows: [] as { count: string }[] };
|
|
if (action) {
|
|
return query<{ count: string }>(
|
|
`SELECT COUNT(*) FROM project_audit_log WHERE action ILIKE $1`,
|
|
[params[0]]
|
|
);
|
|
}
|
|
return query<{ count: string }>(`SELECT COUNT(*) FROM project_audit_log`);
|
|
}
|