Files
Epicnabbo-Catalogus-Updated…/src/features/housekeeping/domains/people/commands/community-commands.ts
T

135 lines
3.7 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 PeopleMutationOperation,
type PeopleMutationService,
peopleMutationService,
} from "../services/mutations";
export const COMMUNITY_COMMAND_IDS = [
"people.guild.disband",
"people.application.decide",
"people.team.change",
"people.ip.action",
"people.vpn.configure",
"people.word-filter.update",
] as const;
export type CommunityCommandId = (typeof COMMUNITY_COMMAND_IDS)[number];
interface CommandOptions<I> {
readonly id: CommunityCommandId;
readonly operation: PeopleMutationOperation;
readonly capability: string;
readonly input: z.ZodType<I>;
}
function communityCommand<I>(
service: Pick<PeopleMutationService, "execute">,
options: CommandOptions<I>,
): HousekeepingCommand<I, unknown> {
return {
id: options.id,
owner: "people",
risk: "sensitive",
capability: anyCapability(options.capability),
input: options.input,
requiresReason: true,
rateLimit: { attempts: 5, windowMs: 60_000 },
execute: (context, input) =>
service.execute(
{
capability: context.capability,
correlationId: context.correlationId,
},
options.operation,
input,
),
};
}
const positiveId = z.number().int().positive();
const requiredText = (max: number) => z.string().min(1).max(max).regex(/\S/u);
export function createCommunityCommands(
service: Pick<PeopleMutationService, "execute">,
) {
return [
communityCommand(service, {
id: "people.guild.disband",
operation: "guild.disband",
capability: PERMS.USERS_EDIT,
input: z.object({ guildId: positiveId }),
}),
communityCommand(service, {
id: "people.application.decide",
operation: "application.decide",
capability: PERMS.USERS_EDIT,
input: z.object({
applicationId: positiveId,
decision: z.literal("dismiss"),
}),
}),
communityCommand(service, {
id: "people.team.change",
operation: "team.change",
capability: PERMS.USERS_EDIT,
input: z.discriminatedUnion("action", [
z.object({
action: z.literal("create"),
rankName: requiredText(255),
badge: z.string().max(255).optional(),
jobDescription: z.string().max(255).optional(),
staffColor: z.string().min(1).max(255).optional(),
hiddenRank: z.boolean().optional(),
}),
z.object({ action: z.literal("delete"), teamId: positiveId }),
]),
}),
communityCommand(service, {
id: "people.ip.action",
operation: "ip.action",
capability: PERMS.SETTINGS_EDIT,
input: z.discriminatedUnion("action", [
z.object({
action: z.enum(["add-whitelist", "add-blacklist"]),
ipAddress: requiredText(255),
asn: z.string().max(255).optional(),
}),
z.object({
action: z.enum(["delete-whitelist", "delete-blacklist"]),
id: positiveId,
}),
]),
}),
communityCommand(service, {
id: "people.vpn.configure",
operation: "vpn.configure",
capability: PERMS.SETTINGS_EDIT,
input: z.object({
enabled: z.boolean(),
provider: z.enum(["none", "proxycheck", "ipqualityscore"]),
apiKey: z.string().max(255),
blockMessage: z.string().max(255),
}),
}),
communityCommand(service, {
id: "people.word-filter.update",
operation: "word-filter.update",
capability: PERMS.WORDFILTER_EDIT,
input: z.discriminatedUnion("action", [
z.object({ action: z.literal("add"), word: requiredText(255) }),
z.object({ action: z.literal("delete"), id: positiveId }),
]),
}),
] as const;
}
export const COMMUNITY_COMMANDS = createCommunityCommands(
peopleMutationService,
);