140 lines
3.9 KiB
TypeScript
140 lines
3.9 KiB
TypeScript
import "server-only";
|
|
|
|
import { z } from "zod";
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
import type { HousekeepingCommand } from "../../../foundation/commands/registry";
|
|
import { anyCapability } from "../../../foundation/contracts";
|
|
import {
|
|
type ContentMutationOperation,
|
|
type ContentMutationService,
|
|
contentMutationService,
|
|
} from "../services/mutations";
|
|
|
|
const CONTENT_COMMAND_DEFINITIONS = [
|
|
["content.editorial.article.change", "article.change", PERMS.NEWS_EDIT],
|
|
["content.media.ad.change", "ad.change", PERMS.PAGES_EDIT],
|
|
["content.media.banner.change", "banner.change", PERMS.BANNERS_EDIT],
|
|
[
|
|
"content.engagement.event-type.change",
|
|
"event-type.change",
|
|
PERMS.EVENTS_EDIT,
|
|
],
|
|
["content.engagement.event.change", "event.change", PERMS.EVENTS_EDIT],
|
|
[
|
|
"content.engagement.event-prize.change",
|
|
"event-prize.change",
|
|
PERMS.EVENTS_EDIT,
|
|
],
|
|
[
|
|
"content.engagement.event-winner.add",
|
|
"event-winner.add",
|
|
PERMS.EVENTS_EDIT,
|
|
],
|
|
["content.engagement.poll.change", "poll.change", PERMS.POLLS_EDIT],
|
|
[
|
|
"content.engagement.poll-question.change",
|
|
"poll-question.change",
|
|
PERMS.POLLS_EDIT,
|
|
],
|
|
["content.media.photo.delete", "photo.delete", PERMS.PAGES_EDIT],
|
|
["content.media.asset.upload", "media.upload", PERMS.PAGES_EDIT],
|
|
["content.media.asset.delete", "media.delete", PERMS.PAGES_EDIT],
|
|
["content.editorial.tag.change", "tag.change", PERMS.PAGES_EDIT],
|
|
["content.engagement.prefix.change", "prefix.change", PERMS.PREFIXES_EDIT],
|
|
[
|
|
"content.engagement.prefix-blacklist.change",
|
|
"prefix-blacklist.change",
|
|
PERMS.PREFIXES_EDIT,
|
|
],
|
|
[
|
|
"content.engagement.prefix-settings.update",
|
|
"prefix-settings.update",
|
|
PERMS.PREFIXES_EDIT,
|
|
],
|
|
["content.help.question.change", "help-question.change", PERMS.PAGES_EDIT],
|
|
[
|
|
"content.editorial.writeable-box.change",
|
|
"writeable-box.change",
|
|
PERMS.PAGES_EDIT,
|
|
],
|
|
[
|
|
"content.help.email-template.change",
|
|
"email-template.change",
|
|
PERMS.PAGES_EDIT,
|
|
],
|
|
["content.brand.theme.update", "theme.update", PERMS.SETTINGS_EDIT],
|
|
[
|
|
"content.brand.theme.apply-preset",
|
|
"theme.apply-preset",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
[
|
|
"content.brand.theme.custom-change",
|
|
"theme.custom-change",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
[
|
|
"content.brand.theme.apply-custom",
|
|
"theme.apply-custom",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
["content.brand.favicon.save", "favicon.save", PERMS.SETTINGS_EDIT],
|
|
["content.brand.favicon.delete", "favicon.delete", PERMS.SETTINGS_EDIT],
|
|
["content.brand.logo.save", "logo.save", PERMS.SETTINGS_EDIT],
|
|
[
|
|
"content.localization.cms.save",
|
|
"translation.cms.save",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
[
|
|
"content.localization.client.save",
|
|
"translation.client.save",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
[
|
|
"content.localization.emulator.save",
|
|
"translation.emulator.save",
|
|
PERMS.SETTINGS_EDIT,
|
|
],
|
|
] as const;
|
|
|
|
export const CONTENT_COMMAND_IDS = CONTENT_COMMAND_DEFINITIONS.map(
|
|
([id]) => id,
|
|
) as ReadonlyArray<(typeof CONTENT_COMMAND_DEFINITIONS)[number][0]>;
|
|
|
|
type ContentCommand = HousekeepingCommand<Record<string, unknown>, unknown> & {
|
|
readonly operation: ContentMutationOperation;
|
|
};
|
|
|
|
const commandInput = z.object({}).catchall(z.unknown());
|
|
|
|
export function createContentCommands(
|
|
service: Pick<ContentMutationService, "execute">,
|
|
): readonly ContentCommand[] {
|
|
return CONTENT_COMMAND_DEFINITIONS.map(
|
|
([id, operation, permission]): ContentCommand => ({
|
|
id,
|
|
owner: "content",
|
|
operation,
|
|
risk: "sensitive",
|
|
capability: anyCapability(permission),
|
|
input: commandInput,
|
|
requiresReason:
|
|
id.startsWith("content.brand.") ||
|
|
id.startsWith("content.localization."),
|
|
rateLimit: { attempts: 10, windowMs: 60_000 },
|
|
execute: (context, input) =>
|
|
service.execute(
|
|
{
|
|
correlationId: context.correlationId,
|
|
expectedActorId: context.capability.actor.id,
|
|
},
|
|
operation,
|
|
input,
|
|
),
|
|
}),
|
|
);
|
|
}
|
|
|
|
export const CONTENT_COMMANDS = createContentCommands(contentMutationService);
|