"use server"; import { revalidateTag } from "next/cache"; import { z } from "zod"; import { type SystemMutationContext, type SystemMutationOperation, systemMutationService, } from "@/features/housekeeping/domains/system/services/mutations"; import { createHousekeepingCapabilityContext } from "@/features/housekeeping/foundation/capability-context"; import type { AdminActionContext } from "@/lib/foundation/types"; import { PERMS } from "@/lib/permission-slugs"; import { adminAction } from "@/lib/safe-action"; import { ActionError, actionOk } from "@/lib/safe-action-shared"; function mutationContext( ctx: Pick, ): SystemMutationContext { return { capability: createHousekeepingCapabilityContext( { id: Number(ctx.session.user.id), rank: Number(ctx.session.user.rank), username: ctx.session.user.username, }, ctx.permissions, ), correlationId: String(ctx.requestId), }; } async function runAccessMutation( ctx: Pick, operation: SystemMutationOperation, input: unknown, ): Promise { const result = await systemMutationService.execute( mutationContext(ctx), operation, input, ); if (result.ok) return result.data; if (result.error.messageKey === "errors.housekeeping.system.rankInUse") { const users = Number(result.error.fieldErrors?.rank?.[0]); if (Number.isInteger(users) && users > 0) { throw new ActionError(`Cannot delete: ${users} users have this rank`); } } if (result.error.messageKey === "errors.housekeeping.system.roleNotFound") { throw new ActionError("Role not found"); } throw new Error(result.error.messageKey); } const createRankSchema = z.object({ rank_name: z.string().trim().min(1).max(25), level: z.coerce.number().int().min(1), }); export const createRank = adminAction( { schema: createRankSchema, permission: PERMS.PERMISSIONS_MANAGE }, async (ctx) => { const result = (await runAccessMutation(ctx, "access.rank.create", { name: ctx.data.rank_name, level: ctx.data.level, })) as { id: number }; revalidateTag("permissions", { expire: 0 }); return actionOk({ id: result.id }); }, ); const deleteRankSchema = z.object({ id: z.coerce.number().int().positive() }); export const deleteRank = adminAction( { schema: deleteRankSchema, permission: PERMS.PERMISSIONS_MANAGE }, async (ctx) => { await runAccessMutation(ctx, "access.rank.delete", ctx.data); revalidateTag("permissions", { expire: 0 }); return actionOk(); }, ); const saveRankSchema = z.object({ id: z.coerce.number().int().positive(), fields: z.record(z.string(), z.union([z.string(), z.number()])), }); export const saveRank = adminAction( { schema: saveRankSchema, permission: PERMS.PERMISSIONS_MANAGE }, async (ctx) => { await runAccessMutation(ctx, "access.rank.update", ctx.data); revalidateTag("permissions", { expire: 0 }); return actionOk(); }, ); const setCmsPermsSchema = z.object({ roleId: z.coerce.number().int().positive(), permissionSlugs: z.array(z.string().trim().min(1)).max(500), }); export const setCmsPermissions = adminAction( { schema: setCmsPermsSchema, permission: PERMS.PERMISSIONS_MANAGE }, async (ctx) => { await runAccessMutation(ctx, "access.permissions.update", ctx.data); revalidateTag("permissions", { expire: 0 }); return actionOk(); }, ); export const repairAdminNavAclGrants = adminAction( { permission: PERMS.PERMISSIONS_MANAGE }, async (ctx) => { const result = (await runAccessMutation( ctx, "access.permissions.repair", {}, )) as { inserted: number }; revalidateTag("permissions", { expire: 0 }); return actionOk({ inserted: result.inserted }); }, );