Files
EpicNext-Cms/src/actions/admin-maintenance.ts
T

65 lines
2.4 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import { systemMutationService } from "@/features/housekeeping/domains/system/services/mutations";
import { createHousekeepingCapabilityContext } from "@/features/housekeeping/foundation/capability-context";
import { createCorrelationId } from "@/features/housekeeping/foundation/correlation";
import { requirePermission } from "@/lib/admin/guard";
import { PERMS } from "@/lib/permissions";
// Maintenance mode lives in three CMS-owned website_settings rows (mirrors
// AtomCMS's MaintenanceToggle Livewire component):
// maintenance_enabled '1' | '0'
// maintenance_message free text (HTML allowed, shown on the splash)
// min_maintenance_login_rank int as string (min rank that may still log in)
// The Laravel login flow reads these via setting() to gate non-staff logins
// while maintenance is on, so the website_settings keys are the source of truth.
function mutationContext(staff: {
id: number;
rank: number;
username: string;
}) {
const matches = (slug: string) => slug === PERMS.SETTINGS_EDIT;
return {
capability: createHousekeepingCapabilityContext(staff, {
isSuperAdmin: false,
has: matches,
hasAny: (...slugs: string[]) => slugs.some(matches),
hasAll: (...slugs: string[]) => slugs.every(matches),
}),
correlationId: createCorrelationId(),
};
}
export async function saveMaintenance(formData: FormData): Promise<void> {
const staff = await requirePermission(PERMS.SETTINGS_EDIT);
// Checkbox: present only when ticked. Normalise to the '1'/'0' string the
// emulator/Laravel side expects.
const enabled = formData.get("enabled") != null ? "1" : "0";
const message = String(formData.get("message") ?? "").normalize("NFC");
// Coerce the rank to a non-negative integer; fall back to AtomCMS's default
// of 5 when the field is blank or garbage.
const rawRank = String(formData.get("min_rank") ?? "")
.normalize("NFC")
.trim();
const parsedRank = Number.parseInt(rawRank, 10);
const minRank =
Number.isFinite(parsedRank) && parsedRank >= 0 ? parsedRank : 5;
const result = await systemMutationService.execute(
mutationContext(staff),
"operations.maintenance.update",
{
enabled: enabled === "1",
message,
minimumLoginRank: minRank,
},
);
if (!result.ok) throw new Error(result.error.messageKey);
revalidatePath("/ase/system/operations/maintenance");
}