123 lines
3.7 KiB
TypeScript
123 lines
3.7 KiB
TypeScript
"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<AdminActionContext, "session" | "permissions" | "requestId">,
|
|
): 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<AdminActionContext, "session" | "permissions" | "requestId">,
|
|
operation: SystemMutationOperation,
|
|
input: unknown,
|
|
): Promise<unknown> {
|
|
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 });
|
|
},
|
|
);
|