"use server"; import { revalidatePath } from "next/cache"; import { requirePermission } from "@/lib/admin/guard"; import { PERMS } from "@/lib/permissions"; import { prisma } from "@/lib/prisma"; import { rcon } from "@/lib/services/rcon"; export async function giveBadge(formData: FormData): Promise { await requirePermission(PERMS.CATALOG_EDIT); const userId = Number(formData.get("userId")); const code = String(formData.get("code") ?? "") .normalize("NFC") .trim() .slice(0, 32); if (!(userId > 0) || code.length === 0) return; // Fire the emulator command so the badge appears live for online users. await rcon.giveBadge(userId, code); // Persist the badge directly so it survives a relog / offline grant. // users_badges has no unique (user_id, badge_code) constraint, so guard // against duplicates and compute the next free slot ourselves. try { const existing = await prisma.usersBadges.findFirst({ where: { userId, badgeCode: code }, select: { id: true }, }); if (!existing) { const max = await prisma.usersBadges.aggregate({ where: { userId }, _max: { slotId: true }, }); const slotId = (max._max.slotId ?? 0) + 1; await prisma.usersBadges.create({ data: { userId, slotId, badgeCode: code }, }); } } catch { // Best-effort: the RCON grant already succeeded for online users. } revalidatePath("/admin/badges"); }