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.
118 lines
4.0 KiB
TypeScript
118 lines
4.0 KiB
TypeScript
import { logError } from "@/lib/logger";
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
import { query } from "@/lib/db";
|
|
import { createAuditLog } from "@/lib/log";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
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 search = searchParams.get("search") || "";
|
|
const offset = (page - 1) * pageSize;
|
|
|
|
let whereClause = "";
|
|
const params: unknown[] = [];
|
|
if (search) {
|
|
whereClause = 'WHERE username ILIKE $1 OR display_name ILIKE $1';
|
|
params.push(`%${search}%`);
|
|
}
|
|
|
|
const countResult = await query<{ count: string }>(
|
|
`SELECT COUNT(*) FROM "user" ${whereClause}`,
|
|
params
|
|
);
|
|
const total = parseInt(countResult.rows[0].count, 10);
|
|
|
|
const result = await query(
|
|
`SELECT u.uid, u.username, u.display_name, u.avatar_url, u.organization,
|
|
u.last_sign_in_at::text as last_sign_in_at, u.created_at::text as created_at,
|
|
COALESCE(up.is_active, true) as is_active,
|
|
ue.email
|
|
FROM "user" u
|
|
LEFT JOIN user_password up ON up.user = u.uid
|
|
LEFT JOIN user_email ue ON ue.user = u.uid
|
|
${whereClause}
|
|
ORDER BY u.created_at DESC
|
|
LIMIT $1 OFFSET $2`,
|
|
params.length > 0
|
|
? [...params, pageSize, offset]
|
|
: [pageSize, offset]
|
|
);
|
|
|
|
const users = result.rows.map((r: Record<string, unknown>) => ({
|
|
uid: r.uid,
|
|
username: r.username,
|
|
display_name: r.display_name,
|
|
avatar_url: r.avatar_url,
|
|
organization: r.organization,
|
|
last_sign_in_at: r.last_sign_in_at,
|
|
created_at: r.created_at,
|
|
is_active: r.is_active,
|
|
email: r.email,
|
|
}));
|
|
|
|
return NextResponse.json({ users, total, page, pageSize });
|
|
} catch (e) {
|
|
logError("Platform users error:", e);
|
|
return NextResponse.json({ error: "服务器错误" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export async function PATCH(req: NextRequest) {
|
|
try {
|
|
const body = await req.json() as {
|
|
ids?: string[];
|
|
action?: "enable" | "disable";
|
|
};
|
|
const { ids = [], action } = body;
|
|
|
|
if (!ids.length) {
|
|
return NextResponse.json({ error: "至少选择一个用户" }, { status: 400 });
|
|
}
|
|
if (!action || !["enable", "disable"].includes(action)) {
|
|
return NextResponse.json({ error: "action 必须是 enable 或 disable" }, { status: 400 });
|
|
}
|
|
|
|
const isActive = action === "enable";
|
|
|
|
// Get user ids from uids
|
|
const uidPlaceholders = ids.map((_, i) => `$${i + 1}`).join(", ");
|
|
const uidResult = await query<{ uid: string }>(
|
|
`SELECT uid FROM "user" WHERE uid IN (${uidPlaceholders})`,
|
|
ids
|
|
);
|
|
const uids = uidResult.rows.map((r) => r.uid);
|
|
|
|
if (!uids.length) {
|
|
return NextResponse.json({ error: "未找到匹配的用户" }, { status: 404 });
|
|
}
|
|
|
|
const uidPlaceholders2 = uids.map((_, i) => `$${i + 1}`).join(", ");
|
|
await query(
|
|
`UPDATE user_password SET is_active = $${uids.length + 1}, updated_at = NOW() WHERE "user" IN (${uidPlaceholders2})`,
|
|
[...uids, isActive]
|
|
);
|
|
|
|
const adminUserId = parseInt(req.headers.get("x-admin-user-id") || "0", 10);
|
|
const adminUsername = req.headers.get("x-admin-username") || "unknown";
|
|
await createAuditLog({
|
|
userId: adminUserId,
|
|
username: adminUsername,
|
|
action: "update",
|
|
resource: "user_batch_status",
|
|
resourceId: `batch(${uids.length})`,
|
|
requestParams: { uidCount: ids.length, userIdCount: uids.length, action },
|
|
ipAddress: req.headers.get("x-forwarded-for") || undefined,
|
|
userAgent: req.headers.get("user-agent") || undefined,
|
|
});
|
|
|
|
return NextResponse.json({ success: true, updated: uids.length });
|
|
} catch (e) {
|
|
logError("Batch update user status error:", e);
|
|
return NextResponse.json({ error: "服务器错误" }, { status: 500 });
|
|
}
|
|
}
|