Your Name ea5a189ae0
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: add agent admin settings access
2026-03-17 23:16:52 +08:00

129 lines
3.7 KiB
TypeScript

import { z } from "zod";
import { requireAdmin } from "@/lib/middleware/admin";
import {
getAllUsers,
getUserById,
updateUser,
deleteUserById,
} from "@/lib/db/queries";
import { ChatSDKError } from "@/lib/errors";
const updateUserSchema = z.object({
id: z.string().uuid(),
role: z.enum(["guest", "regular", "admin", "agent_admin"]).optional(),
isHighVip: z.boolean().optional(),
isActive: z.boolean().optional(),
email: z.string().email().optional(),
monthlyImageLimit: z.number().int().min(0).nullable().optional(),
pointsBalance: z.number().int().min(0).nullable().optional(),
giftPoints: z.number().int().min(1).max(100000).optional(),
deductPoints: z.number().int().min(1).max(100000).optional(),
pointsNote: z.string().max(200).optional(),
});
export async function GET(request: Request) {
try {
await requireAdmin();
const { searchParams } = new URL(request.url);
const page = Number.parseInt(searchParams.get("page") || "1", 10);
const limit = Number.parseInt(searchParams.get("limit") || "10", 10);
const search = searchParams.get("search") || "";
const offset = (page - 1) * limit;
const { users, total } = await getAllUsers({ limit, offset, search });
return Response.json({
users,
total,
page,
limit,
totalPages: Math.ceil(total / limit)
});
} catch (error) {
if (error instanceof ChatSDKError) {
return error.toResponse();
}
return new ChatSDKError("offline:admin").toResponse();
}
}
export async function PATCH(request: Request) {
try {
await requireAdmin();
const body = await request.json();
const { id, role, isHighVip, isActive, email, monthlyImageLimit, pointsBalance, giftPoints, deductPoints, pointsNote } =
updateUserSchema.parse(body);
if (giftPoints !== undefined && deductPoints !== undefined) {
return new ChatSDKError("bad_request:api", "giftPoints and deductPoints cannot be used together").toResponse();
}
if (deductPoints !== undefined) {
const existingUser = await getUserById({ id });
const currentBalance = Math.max(0, Number(existingUser?.pointsBalance || 0));
if (!existingUser) {
return new ChatSDKError("bad_request:api", "User not found").toResponse();
}
if (currentBalance < deductPoints) {
return new ChatSDKError(
"bad_request:api",
`积分不足,当前余额 ${currentBalance},无法扣减 ${deductPoints}`
).toResponse();
}
}
const session = await requireAdmin();
const result = await updateUser({
id,
role,
isHighVip,
isActive,
email,
monthlyImageLimit,
pointsBalance,
giftPoints,
deductPoints,
pointsNote,
operatorId: session.user.id,
});
if (result.length === 0) {
return new ChatSDKError("bad_request:api", "User not found").toResponse();
}
return Response.json({ user: result[0] });
} catch (error) {
if (error instanceof ChatSDKError) {
return error.toResponse();
}
if (error instanceof z.ZodError) {
return new ChatSDKError("bad_request:api", error.message).toResponse();
}
return new ChatSDKError("offline:admin").toResponse();
}
}
export async function DELETE(request: Request) {
try {
await requireAdmin();
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");
if (!id) {
return new ChatSDKError("bad_request:api", "User ID is required").toResponse();
}
await deleteUserById({ id });
return Response.json({ success: true });
} catch (error) {
if (error instanceof ChatSDKError) {
return error.toResponse();
}
return new ChatSDKError("offline:admin").toResponse();
}
}