import "server-only"; import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { admin, required } from "./supabase"; import { ServiceError, checkServiceError } from "./service-error"; import { prefixUpdateSchema } from "@/shared/profile-appearance"; export async function moderatorUsersApi( request: NextRequest, path: string[], reviewer: string, jsonBody: (request: NextRequest) => Promise, ) { const db = admin(); const columns = "id,display_name,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon" as const; const respond = (body: unknown) => NextResponse.json(body, { headers: { "Cache-Control": "no-store" } }); if (request.method === "GET" && path.length === 2) { const search = (request.nextUrl.searchParams.get("q") ?? "") .trim() .slice(0, 64); let query = db .from("profiles") .select(columns) .order("display_name") .order("id") .limit(50); if (search) { if (z.string().uuid().safeParse(search).success) query = query.eq("id", search); else query = query.ilike( "display_name", "%" + search.replace(/[\\%_]/g, "\\$&") + "%", ); } return respond({ users: required(await query) }); } if (request.method === "PATCH" && path.length === 3) { const id = z.string().uuid().parse(path[2]), body = prefixUpdateSchema.parse(await jsonBody(request)); const updated = await db.rpc("set_user_prefix", { p_reviewer: reviewer, p_user: id, p_prefix: body.prefix, p_icon: body.icon, }); checkServiceError(updated.error); const result = await db .from("profiles") .select(columns) .eq("id", id) .maybeSingle(); if (result.error) required(result); if (!result.data) throw new ServiceError("Player not found", 404); return respond({ user: result.data }); } return NextResponse.json({ error: "Not found" }, { status: 404 }); }