diff --git a/backend/src/plugins/ModActions/ModActionsPlugin.ts b/backend/src/plugins/ModActions/ModActionsPlugin.ts index ba19a0b0..16bf587f 100644 --- a/backend/src/plugins/ModActions/ModActionsPlugin.ts +++ b/backend/src/plugins/ModActions/ModActionsPlugin.ts @@ -84,6 +84,7 @@ const defaultOptions = { can_deletecase: false, can_act_as_other: false, create_cases_for_manual_actions: true, + reason_aliases: {}, }, overrides: [ { diff --git a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts index b28b1eeb..8d862437 100644 --- a/backend/src/plugins/ModActions/commands/AddCaseCmd.ts +++ b/backend/src/plugins/ModActions/commands/AddCaseCmd.ts @@ -1,14 +1,13 @@ -import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { Case } from "../../../data/entities/Case"; -import { LogType } from "../../../data/LogType"; import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin"; import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils"; import { resolveMember, resolveUser } from "../../../utils"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { modActionsCmd } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "../functions/parseReason"; const opts = { mod: ct.member({ option: true }), @@ -60,8 +59,8 @@ export const AddCaseCmd = modActionsCmd({ sendErrorMessage(pluginData, msg.channel, "Cannot add case: invalid case type"); return; } - - const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]); + const config = pluginData.config.get(); + const reason = parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()]))!; // Create the case const casesPlugin = pluginData.getPlugin(CasesPlugin); diff --git a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts index 1df592b6..9d46dc87 100644 --- a/backend/src/plugins/ModActions/commands/ForcebanCmd.ts +++ b/backend/src/plugins/ModActions/commands/ForcebanCmd.ts @@ -11,6 +11,7 @@ import { ignoreEvent } from "../functions/ignoreEvent"; import { isBanned } from "../functions/isBanned"; import { IgnoredEventType, modActionsCmd } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "../functions/parseReason"; const opts = { mod: ct.member({ option: true }), @@ -61,8 +62,8 @@ export const ForcebanCmd = modActionsCmd({ mod = args.mod; } - - const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]); + const config = pluginData.config.get(); + const reason = parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()]))!; ignoreEvent(pluginData, IgnoredEventType.Ban, user.id); pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id); diff --git a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts index 83044c85..77c51d66 100644 --- a/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassUnbanCmd.ts @@ -1,6 +1,5 @@ import { Snowflake, TextChannel } from "discord.js"; import { waitForReply } from "knub/dist/helpers"; -import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; @@ -11,6 +10,7 @@ import { ignoreEvent } from "../functions/ignoreEvent"; import { isBanned } from "../functions/isBanned"; import { IgnoredEventType, modActionsCmd } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "../functions/parseReason"; export const MassunbanCmd = modActionsCmd({ trigger: "massunban", @@ -37,8 +37,11 @@ export const MassunbanCmd = modActionsCmd({ sendErrorMessage(pluginData, msg.channel, "Cancelled"); return; } - - const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, [...msg.attachments.values()]); + const config = pluginData.config.get(); + const unbanReason = parseReason( + config, + formatReasonWithAttachments(unbanReasonReply.content, [...msg.attachments.values()]), + )!; // Ignore automatic unban cases and logs for these users // We'll create our own cases below and post a single "mass unbanned" log instead diff --git a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts index ecd696df..46ac2917 100644 --- a/backend/src/plugins/ModActions/commands/MassmuteCmd.ts +++ b/backend/src/plugins/ModActions/commands/MassmuteCmd.ts @@ -1,6 +1,5 @@ import { Snowflake, TextChannel } from "discord.js"; import { waitForReply } from "knub/dist/helpers"; -import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { LogType } from "../../../data/LogType"; import { logger } from "../../../logger"; @@ -9,6 +8,7 @@ import { canActOn, sendErrorMessage, sendSuccessMessage } from "../../../pluginU import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { modActionsCmd } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "../functions/parseReason"; export const MassmuteCmd = modActionsCmd({ trigger: "massmute", @@ -40,7 +40,11 @@ export const MassmuteCmd = modActionsCmd({ return; } - const muteReason = formatReasonWithAttachments(muteReasonReceived.content, [...msg.attachments.values()]); + const config = pluginData.config.get(); + const muteReason = parseReason( + config, + formatReasonWithAttachments(muteReasonReceived.content, [...msg.attachments.values()]), + ); // Verify we can act upon all users for (const userId of args.userIds) { diff --git a/backend/src/plugins/ModActions/commands/UnbanCmd.ts b/backend/src/plugins/ModActions/commands/UnbanCmd.ts index 2c9bbfd3..8b9ab7e4 100644 --- a/backend/src/plugins/ModActions/commands/UnbanCmd.ts +++ b/backend/src/plugins/ModActions/commands/UnbanCmd.ts @@ -1,5 +1,4 @@ import { Snowflake } from "discord.js"; -import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { commandTypeHelpers as ct } from "../../../commandTypes"; import { CaseTypes } from "../../../data/CaseTypes"; import { LogType } from "../../../data/LogType"; @@ -11,6 +10,7 @@ import { ignoreEvent } from "../functions/ignoreEvent"; import { IgnoredEventType, modActionsCmd } from "../types"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { clearExpiringTempban } from "../../../data/loops/expiringTempbansLoop"; +import { parseReason } from "../functions/parseReason"; const opts = { mod: ct.member({ option: true }), @@ -49,7 +49,8 @@ export const UnbanCmd = modActionsCmd({ } pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id); - const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]); + const config = pluginData.config.get(); + const reason = parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()])); try { ignoreEvent(pluginData, IgnoredEventType.Unban, user.id); diff --git a/backend/src/plugins/ModActions/commands/WarnCmd.ts b/backend/src/plugins/ModActions/commands/WarnCmd.ts index 03d79b76..ac0c4045 100644 --- a/backend/src/plugins/ModActions/commands/WarnCmd.ts +++ b/backend/src/plugins/ModActions/commands/WarnCmd.ts @@ -7,6 +7,7 @@ import { waitForButtonConfirm } from "../../../utils/waitForInteraction"; import { CasesPlugin } from "../../Cases/CasesPlugin"; import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments"; import { isBanned } from "../functions/isBanned"; +import { parseReason } from "../functions/parseReason"; import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs"; import { warnMember } from "../functions/warnMember"; import { modActionsCmd } from "../types"; @@ -63,7 +64,7 @@ export const WarnCmd = modActionsCmd({ } const config = pluginData.config.get(); - const reason = formatReasonWithAttachments(args.reason, [...msg.attachments.values()]); + const reason = parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()]))!; const casesPlugin = pluginData.getPlugin(CasesPlugin); const priorWarnAmount = await casesPlugin.getCaseTypeAmountForUserId(memberToWarn.id, CaseTypes.Warn); diff --git a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts index 92178edc..eaeb22d8 100644 --- a/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualKickMemberCmd.ts @@ -9,6 +9,7 @@ import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; import { ignoreEvent } from "./ignoreEvent"; import { isBanned } from "./isBanned"; import { kickMember } from "./kickMember"; +import { parseReason } from "./parseReason"; import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs"; export async function actualKickMemberCmd( @@ -67,7 +68,8 @@ export async function actualKickMemberCmd( return; } - const reason = formatReasonWithAttachments(args.reason, msg.attachments); + const config = pluginData.config.get(); + const reason = parseReason(config, formatReasonWithAttachments(args.reason, msg.attachments)); const kickResult = await kickMember(pluginData, memberToKick, reason, { contactMethods, diff --git a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts index 6a750fd5..6258602d 100644 --- a/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualMuteUserCmd.ts @@ -9,6 +9,7 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin"; import { MuteResult } from "../../Mutes/types"; import { ModActionsPluginType } from "../types"; import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; +import { parseReason } from "./parseReason"; import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs"; /** @@ -42,7 +43,10 @@ export async function actualMuteUserCmd( } const timeUntilUnmute = args.time && humanizeDuration(args.time); - const reason = args.reason ? formatReasonWithAttachments(args.reason, [...msg.attachments.values()]) : undefined; + const config = pluginData.config.get(); + const reason = args.reason + ? parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()])) + : undefined; let muteResult: MuteResult; const mutesPlugin = pluginData.getPlugin(MutesPlugin); diff --git a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts index 46ab7be6..aa815eb0 100644 --- a/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts +++ b/backend/src/plugins/ModActions/functions/actualUnmuteUserCmd.ts @@ -6,6 +6,7 @@ import { hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pl import { asSingleLine, UnknownUser } from "../../../utils"; import { ModActionsPluginType } from "../types"; import { formatReasonWithAttachments } from "./formatReasonWithAttachments"; +import { parseReason } from "./parseReason"; export async function actualUnmuteCmd( pluginData: GuildPluginData, @@ -27,7 +28,10 @@ export async function actualUnmuteCmd( pp = msg.author; } - const reason = args.reason ? formatReasonWithAttachments(args.reason, [...msg.attachments.values()]) : undefined; + const config = pluginData.config.get(); + const reason = args.reason + ? parseReason(config, formatReasonWithAttachments(args.reason, [...msg.attachments.values()])) + : undefined; const mutesPlugin = pluginData.getPlugin(MutesPlugin); const result = await mutesPlugin.unmuteUser(user.id, args.time, { diff --git a/backend/src/plugins/ModActions/functions/banUserId.ts b/backend/src/plugins/ModActions/functions/banUserId.ts index 21d02738..a0eab649 100644 --- a/backend/src/plugins/ModActions/functions/banUserId.ts +++ b/backend/src/plugins/ModActions/functions/banUserId.ts @@ -20,6 +20,7 @@ import { getDefaultContactMethods } from "./getDefaultContactMethods"; import { ignoreEvent } from "./ignoreEvent"; import { LogsPlugin } from "../../Logs/LogsPlugin"; import { registerExpiringTempban } from "../../../data/loops/expiringTempbansLoop"; +import { parseReason } from "./parseReason"; /** * Ban the specified user id, whether or not they're actually on the server at the time. Generates a case. @@ -39,6 +40,7 @@ export async function banUserId( error: "Invalid user", }; } + if (reason) reason = parseReason(config, reason); // Attempt to message the user *before* banning them, as doing it after may not be possible let notifyResult: UserNotificationResult = { method: null, success: true }; diff --git a/backend/src/plugins/ModActions/functions/kickMember.ts b/backend/src/plugins/ModActions/functions/kickMember.ts index d70722a1..971687ca 100644 --- a/backend/src/plugins/ModActions/functions/kickMember.ts +++ b/backend/src/plugins/ModActions/functions/kickMember.ts @@ -10,6 +10,7 @@ import { IgnoredEventType, KickOptions, KickResult, ModActionsPluginType } from import { getDefaultContactMethods } from "./getDefaultContactMethods"; import { ignoreEvent } from "./ignoreEvent"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "./parseReason"; /** * Kick the specified server member. Generates a case. @@ -25,6 +26,7 @@ export async function kickMember( // Attempt to message the user *before* kicking them, as doing it after may not be possible let notifyResult: UserNotificationResult = { method: null, success: true }; if (reason) { + reason = parseReason(config, reason); const contactMethods = kickOptions?.contactMethods ? kickOptions.contactMethods : getDefaultContactMethods(pluginData, "kick"); diff --git a/backend/src/plugins/ModActions/functions/parseReason.ts b/backend/src/plugins/ModActions/functions/parseReason.ts new file mode 100644 index 00000000..089252d0 --- /dev/null +++ b/backend/src/plugins/ModActions/functions/parseReason.ts @@ -0,0 +1,12 @@ +const MAX_REASON_LENGTH = 512; + +export function parseReason(config: any, reason?: string): string | undefined { + if (!reason) return reason; + if (config?.reason_aliases) { + reason = config.reason_aliases![reason.toLowerCase()] ?? reason; + } + if (reason!.length > MAX_REASON_LENGTH) { + reason = reason!.substring(0, MAX_REASON_LENGTH - 6) + " [...]"; + } + return reason; +} diff --git a/backend/src/plugins/ModActions/functions/warnMember.ts b/backend/src/plugins/ModActions/functions/warnMember.ts index e0f22c8f..f5324050 100644 --- a/backend/src/plugins/ModActions/functions/warnMember.ts +++ b/backend/src/plugins/ModActions/functions/warnMember.ts @@ -1,8 +1,7 @@ import { GuildMember, Snowflake } from "discord.js"; import { GuildPluginData } from "knub"; -import { memberToTemplateSafeMember, userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; +import { userToTemplateSafeUser } from "../../../utils/templateSafeObjects"; import { CaseTypes } from "../../../data/CaseTypes"; -import { LogType } from "../../../data/LogType"; import { renderTemplate, TemplateSafeValueContainer } from "../../../templateFormatter"; import { createUserNotificationError, notifyUser, resolveUser, ucfirst, UserNotificationResult } from "../../../utils"; import { waitForButtonConfirm } from "../../../utils/waitForInteraction"; @@ -10,6 +9,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin"; import { ModActionsPluginType, WarnOptions, WarnResult } from "../types"; import { getDefaultContactMethods } from "./getDefaultContactMethods"; import { LogsPlugin } from "../../Logs/LogsPlugin"; +import { parseReason } from "./parseReason"; export async function warnMember( pluginData: GuildPluginData, @@ -18,7 +18,7 @@ export async function warnMember( warnOptions: WarnOptions = {}, ): Promise { const config = pluginData.config.get(); - + reason = parseReason(config, reason)!; let notifyResult: UserNotificationResult; if (config.warn_message) { const warnMessage = await renderTemplate( diff --git a/backend/src/plugins/ModActions/types.ts b/backend/src/plugins/ModActions/types.ts index 16e8e15e..a705fb51 100644 --- a/backend/src/plugins/ModActions/types.ts +++ b/backend/src/plugins/ModActions/types.ts @@ -46,6 +46,7 @@ export const ConfigSchema = t.type({ can_deletecase: t.boolean, can_act_as_other: t.boolean, create_cases_for_manual_actions: t.boolean, + reason_aliases: tNullable(t.record(t.string, t.string)), }); export type TConfigSchema = t.TypeOf;