"use server"; import { randomBytes } from "node:crypto"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { Prisma } from "@prisma/client"; import { prisma } from "./prisma"; import { requireCurrentUser, userIsAdmin } from "./session"; async function requireAdmin() { const user = await requireCurrentUser(); if (!userIsAdmin(user)) redirect("/dashboard"); return user; } export async function disableUser(formData: FormData) { const admin = await requireAdmin(); const userId = String(formData.get("userId") || ""); if (!userId || userId === admin.id) return; await prisma.user.update({ where: { id: userId }, data: { disabledAt: new Date() } }); await audit(admin.id, "admin.user.disable", { userId }); revalidateAdmin(); } export async function enableUser(formData: FormData) { const admin = await requireAdmin(); const userId = String(formData.get("userId") || ""); if (!userId) return; await prisma.user.update({ where: { id: userId }, data: { disabledAt: null } }); await audit(admin.id, "admin.user.enable", { userId }); revalidateAdmin(); } export async function grantAdminRole(formData: FormData) { const admin = await requireAdmin(); const userId = String(formData.get("userId") || ""); if (!userId) return; const role = await prisma.role.upsert({ where: { name: "admin" }, update: {}, create: { name: "admin", description: "Full system administrator" } }); await prisma.userRole.upsert({ where: { userId_roleId: { userId, roleId: role.id } }, update: {}, create: { userId, roleId: role.id } }); await audit(admin.id, "admin.user.role.grant", { userId, role: "admin" }); revalidateAdmin(); } export async function revokeAdminRole(formData: FormData) { const admin = await requireAdmin(); const userId = String(formData.get("userId") || ""); if (!userId || userId === admin.id) return; const role = await prisma.role.findUnique({ where: { name: "admin" } }); if (!role) return; await prisma.userRole.deleteMany({ where: { userId, roleId: role.id } }); await audit(admin.id, "admin.user.role.revoke", { userId, role: "admin" }); revalidateAdmin(); } export async function createInstanceInvite(formData: FormData) { const admin = await requireAdmin(); const roomId = String(formData.get("roomId") || "") || null; const expiresDays = Number(formData.get("expiresDays") || 0); const expiresAt = Number.isFinite(expiresDays) && expiresDays > 0 ? new Date(Date.now() + expiresDays * 24 * 60 * 60 * 1000) : null; const invite = await prisma.invite.create({ data: { code: randomBytes(12).toString("base64url"), creatorId: admin.id, roomId, expiresAt } }); await audit(admin.id, "admin.invite.create", { inviteId: invite.id, roomId }); revalidateAdmin(); redirect("/admin?tab=Invites&saved=1"); } export async function revokeInvite(formData: FormData) { const admin = await requireAdmin(); const inviteId = String(formData.get("inviteId") || ""); if (!inviteId) return; await prisma.invite.update({ where: { id: inviteId }, data: { status: "REVOKED" } }); await audit(admin.id, "admin.invite.revoke", { inviteId }); revalidateAdmin(); } async function audit(actorId: string, action: string, metadata: Prisma.InputJsonObject) { await prisma.auditEvent.create({ data: { actorId, action, metadata } }); } function revalidateAdmin() { revalidatePath("/admin"); revalidatePath("/dashboard"); revalidatePath("/rooms"); }