import { NextResponse, type NextRequest } from "next/server"; import { requireApiAdmin } from "@/lib/api-auth"; import { getUserById, updateUserRecord } from "@/lib/db"; import { hashPassword, toPublicUser } from "@/lib/auth"; import { getQuotaSnapshotForUser } from "@/lib/quota"; import { jsonError, normalizeError } from "@/lib/http"; export const runtime = "nodejs"; export async function PATCH( request: NextRequest, { params }: { params: Promise<{ id: string }> }, ) { try { const adminUser = requireApiAdmin(request); const body = (await request.json()) as { role?: unknown; monthlyQuota?: unknown; isActive?: unknown; password?: unknown; }; const { id } = await params; const targetUser = getUserById(id); const monthlyQuota = typeof body?.monthlyQuota === "number" || typeof body?.monthlyQuota === "string" ? body.monthlyQuota : undefined; const password = typeof body?.password === "string" ? body.password : ""; if (!targetUser) { return jsonError("用户不存在。", 404); } if (targetUser.id === adminUser.id) { if (body?.role && body.role !== "admin") { return jsonError("不能移除当前管理员自己的 admin 身份。", 400); } if (body?.isActive === false) { return jsonError("不能禁用当前管理员自己的账号。", 400); } } const updatedUser = updateUserRecord(targetUser.id, { role: body?.role === "admin" ? "admin" : "user", monthlyQuota: body?.role === "admin" ? null : monthlyQuota === null || monthlyQuota === "" ? null : monthlyQuota, isActive: body?.isActive === undefined ? targetUser.isActive : Boolean(body.isActive), passwordHash: password.trim().length >= 8 ? hashPassword(password) : undefined, }); if (!updatedUser) { return jsonError("用户不存在。", 404); } const publicUser = toPublicUser(updatedUser); if (!publicUser) { return jsonError("保存用户失败。", 500); } const quota = getQuotaSnapshotForUser(publicUser); return NextResponse.json({ ok: true, user: { ...publicUser, usedThisPeriod: quota.used, remaining: quota.remaining, limit: quota.limit, isUnlimited: quota.isUnlimited, }, }); } catch (error) { const normalizedError = normalizeError(error, "保存用户失败。"); return jsonError(normalizedError.message, normalizedError.statusCode); } }