diff --git a/backend/src/plugins/Automod/AutomodPlugin.ts b/backend/src/plugins/Automod/AutomodPlugin.ts index d99c8240..0df56910 100644 --- a/backend/src/plugins/Automod/AutomodPlugin.ts +++ b/backend/src/plugins/Automod/AutomodPlugin.ts @@ -93,6 +93,23 @@ const configPreprocessor: ConfigPreprocessorFn = options => { } } + if (rule["actions"]) { + for (const actionName in rule["actions"]) { + if (!availableActions[actionName]) { + throw new StrictValidationError([`Unknown action '${actionName}' in rule '${rule.name}'`]); + } + + const actionBlueprint = availableActions[actionName]; + const actionConfig = rule["actions"][actionName]; + + if (typeof actionConfig !== "object" || Array.isArray(actionConfig) || actionConfig == null) { + rule["actions"][actionName] = actionConfig; + } else { + rule["actions"][actionName] = configUtils.mergeConfig(actionBlueprint.defaultConfig, actionConfig); + } + } + } + // Enable logging of automod actions by default if (rule["actions"]) { for (const actionName in rule.actions) { diff --git a/backend/src/plugins/Automod/actions/addRoles.ts b/backend/src/plugins/Automod/actions/addRoles.ts index 05829a12..0c48f2ac 100644 --- a/backend/src/plugins/Automod/actions/addRoles.ts +++ b/backend/src/plugins/Automod/actions/addRoles.ts @@ -7,6 +7,7 @@ import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; export const AddRolesAction = automodAction({ configType: t.array(t.string), + defaultConfig: [], async apply({ pluginData, contexts, actionConfig }) { const members = unique(contexts.map(c => c.member).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/alert.ts b/backend/src/plugins/Automod/actions/alert.ts index c72d874b..7c8e724b 100644 --- a/backend/src/plugins/Automod/actions/alert.ts +++ b/backend/src/plugins/Automod/actions/alert.ts @@ -14,6 +14,8 @@ export const AlertAction = automodAction({ text: t.string, }), + defaultConfig: {}, + async apply({ pluginData, contexts, actionConfig, ruleName, matchResult }) { const channel = pluginData.guild.channels.get(actionConfig.channel); const logs = pluginData.getPlugin(LogsPlugin); diff --git a/backend/src/plugins/Automod/actions/ban.ts b/backend/src/plugins/Automod/actions/ban.ts index 4a0bf3c0..0cc5da22 100644 --- a/backend/src/plugins/Automod/actions/ban.ts +++ b/backend/src/plugins/Automod/actions/ban.ts @@ -13,6 +13,10 @@ export const BanAction = automodAction({ deleteMessageDays: tNullable(t.number), }), + defaultConfig: { + notify: null, // Use defaults from ModActions + }, + async apply({ pluginData, contexts, actionConfig, matchResult }) { const reason = actionConfig.reason || "Kicked automatically"; const contactMethods = resolveActionContactMethods(pluginData, actionConfig); @@ -20,9 +24,7 @@ export const BanAction = automodAction({ const caseArgs = { modId: pluginData.client.user.id, - extraNotes: [ - matchResult.summary, // TODO - ], + extraNotes: [matchResult.fullSummary], }; const userIdsToBan = unique(contexts.map(c => c.user?.id).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/changeNickname.ts b/backend/src/plugins/Automod/actions/changeNickname.ts index b3bf512b..eb39562d 100644 --- a/backend/src/plugins/Automod/actions/changeNickname.ts +++ b/backend/src/plugins/Automod/actions/changeNickname.ts @@ -9,6 +9,8 @@ export const ChangeNicknameAction = automodAction({ name: t.string, }), + defaultConfig: {}, + async apply({ pluginData, contexts, actionConfig }) { const members = unique(contexts.map(c => c.member).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/clean.ts b/backend/src/plugins/Automod/actions/clean.ts index 67fbf0b1..1bebe626 100644 --- a/backend/src/plugins/Automod/actions/clean.ts +++ b/backend/src/plugins/Automod/actions/clean.ts @@ -4,6 +4,7 @@ import { LogType } from "../../../data/LogType"; export const CleanAction = automodAction({ configType: t.boolean, + defaultConfig: false, async apply({ pluginData, contexts }) { const messageIdsToDeleteByChannelId: Map = new Map(); diff --git a/backend/src/plugins/Automod/actions/exampleAction.ts b/backend/src/plugins/Automod/actions/exampleAction.ts index ba5c0e27..760b2879 100644 --- a/backend/src/plugins/Automod/actions/exampleAction.ts +++ b/backend/src/plugins/Automod/actions/exampleAction.ts @@ -6,6 +6,8 @@ export const ExampleAction = automodAction({ someValue: t.string, }), + defaultConfig: {}, + async apply({ pluginData, contexts, actionConfig }) { // TODO: Everything }, diff --git a/backend/src/plugins/Automod/actions/kick.ts b/backend/src/plugins/Automod/actions/kick.ts index 5b9044f1..7d4f688a 100644 --- a/backend/src/plugins/Automod/actions/kick.ts +++ b/backend/src/plugins/Automod/actions/kick.ts @@ -12,15 +12,17 @@ export const KickAction = automodAction({ notifyChannel: tNullable(t.string), }), + defaultConfig: { + notify: null, // Use defaults from ModActions + }, + async apply({ pluginData, contexts, actionConfig, matchResult }) { const reason = actionConfig.reason || "Kicked automatically"; const contactMethods = resolveActionContactMethods(pluginData, actionConfig); const caseArgs = { modId: pluginData.client.user.id, - extraNotes: [ - matchResult.summary, // TODO - ], + extraNotes: [matchResult.fullSummary], }; const userIdsToKick = unique(contexts.map(c => c.user?.id).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/log.ts b/backend/src/plugins/Automod/actions/log.ts index cc1a91c3..a6e5455b 100644 --- a/backend/src/plugins/Automod/actions/log.ts +++ b/backend/src/plugins/Automod/actions/log.ts @@ -6,6 +6,7 @@ import { stripObjectToScalars } from "../../../utils"; export const LogAction = automodAction({ configType: t.boolean, + defaultConfig: true, async apply({ pluginData, contexts, ruleName, matchResult }) { const safeUsers = contexts.map(c => c.user && stripObjectToScalars(c.user)).filter(Boolean); diff --git a/backend/src/plugins/Automod/actions/mute.ts b/backend/src/plugins/Automod/actions/mute.ts index a11ac218..aa9d4443 100644 --- a/backend/src/plugins/Automod/actions/mute.ts +++ b/backend/src/plugins/Automod/actions/mute.ts @@ -14,6 +14,10 @@ export const MuteAction = automodAction({ notifyChannel: tNullable(t.string), }), + defaultConfig: { + notify: null, // Use defaults from ModActions + }, + async apply({ pluginData, contexts, actionConfig, matchResult }) { const duration = actionConfig.duration ? convertDelayStringToMS(actionConfig.duration) : null; const reason = actionConfig.reason || "Muted automatically"; @@ -21,9 +25,7 @@ export const MuteAction = automodAction({ const caseArgs = { modId: pluginData.client.user.id, - extraNotes: [ - matchResult.summary, // TODO - ], + extraNotes: [matchResult.fullSummary], }; const userIdsToMute = unique(contexts.map(c => c.user?.id).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/removeRoles.ts b/backend/src/plugins/Automod/actions/removeRoles.ts index 5b692c89..2f824435 100644 --- a/backend/src/plugins/Automod/actions/removeRoles.ts +++ b/backend/src/plugins/Automod/actions/removeRoles.ts @@ -8,6 +8,8 @@ import { ModActionsPlugin } from "../../ModActions/ModActionsPlugin"; export const RemoveRolesAction = automodAction({ configType: t.array(t.string), + defaultConfig: [], + async apply({ pluginData, contexts, actionConfig }) { const members = unique(contexts.map(c => c.member).filter(Boolean)); diff --git a/backend/src/plugins/Automod/actions/reply.ts b/backend/src/plugins/Automod/actions/reply.ts index 66a164f9..9c808a2e 100644 --- a/backend/src/plugins/Automod/actions/reply.ts +++ b/backend/src/plugins/Automod/actions/reply.ts @@ -23,6 +23,8 @@ export const ReplyAction = automodAction({ }), ]), + defaultConfig: {}, + async apply({ pluginData, contexts, actionConfig }) { const contextsWithTextChannels = contexts .filter(c => c.message?.channel_id) diff --git a/backend/src/plugins/Automod/actions/setAntiraidLevel.ts b/backend/src/plugins/Automod/actions/setAntiraidLevel.ts index 9a7ccc0e..99a5900b 100644 --- a/backend/src/plugins/Automod/actions/setAntiraidLevel.ts +++ b/backend/src/plugins/Automod/actions/setAntiraidLevel.ts @@ -4,6 +4,7 @@ import { setAntiraidLevel } from "../functions/setAntiraidLevel"; export const SetAntiraidLevelAction = automodAction({ configType: t.string, + defaultConfig: null, async apply({ pluginData, contexts, actionConfig }) { setAntiraidLevel(pluginData, actionConfig); diff --git a/backend/src/plugins/Automod/actions/warn.ts b/backend/src/plugins/Automod/actions/warn.ts index 279ba1dc..972ec9d2 100644 --- a/backend/src/plugins/Automod/actions/warn.ts +++ b/backend/src/plugins/Automod/actions/warn.ts @@ -12,15 +12,17 @@ export const WarnAction = automodAction({ notifyChannel: tNullable(t.string), }), + defaultConfig: { + notify: null, // Use defaults from ModActions + }, + async apply({ pluginData, contexts, actionConfig, matchResult }) { const reason = actionConfig.reason || "Warned automatically"; const contactMethods = resolveActionContactMethods(pluginData, actionConfig); const caseArgs = { modId: pluginData.client.user.id, - extraNotes: [ - matchResult.summary, // TODO - ], + extraNotes: [matchResult.fullSummary], }; const userIdsToWarn = unique(contexts.map(c => c.user?.id).filter(Boolean)); diff --git a/backend/src/plugins/Automod/functions/runAutomod.ts b/backend/src/plugins/Automod/functions/runAutomod.ts index 2f146240..0d3bb2f0 100644 --- a/backend/src/plugins/Automod/functions/runAutomod.ts +++ b/backend/src/plugins/Automod/functions/runAutomod.ts @@ -55,13 +55,16 @@ export async function runAutomod(pluginData: PluginData, cont return; } - matchResult.summary = await trigger.renderMatchInformation({ - ruleName, - pluginData, - contexts, - matchResult, - triggerConfig, - }); + matchResult.summary = + (await trigger.renderMatchInformation({ + ruleName, + pluginData, + contexts, + matchResult, + triggerConfig, + })) ?? ""; + + matchResult.fullSummary = `Triggered automod rule **${ruleName}**\n${matchResult.summary}`.trim(); break triggerLoop; } diff --git a/backend/src/plugins/Automod/helpers.ts b/backend/src/plugins/Automod/helpers.ts index 0dcce48f..4bb8154d 100644 --- a/backend/src/plugins/Automod/helpers.ts +++ b/backend/src/plugins/Automod/helpers.ts @@ -10,6 +10,7 @@ export interface AutomodTriggerMatchResult { silentClean?: boolean; // TODO: Maybe generalize to a "silent" value in general, which mutes alert/log summary?: string; + fullSummary?: string; } type AutomodTriggerMatchFn = (meta: { @@ -61,6 +62,8 @@ type AutomodActionApplyFn = (meta: { export interface AutomodActionBlueprint { configType: TConfigType; + defaultConfig: Partial>; + apply: AutomodActionApplyFn>; }