From 9d0d61893e1a3600665b50c701c0f9285e41d2ea Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:14:52 +0100 Subject: [PATCH 01/17] Update configs --- .github/config.json | 6 ++++++ config.template.json | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/config.json b/.github/config.json index f8bffbb6..6a48f59c 100644 --- a/.github/config.json +++ b/.github/config.json @@ -109,5 +109,11 @@ "winnerRoleId": "1045422896740311070", "emotifiziererRoleId": "893179190709477410", "lootRoleAsseGuardRoleId": "1268706685753622529" + }, + + "emoji": { + "alarmEmojiId": "986292638204448838", + "sadHamsterEmojiId": "896110620108263424", + "trichterEmojiId": "986290070908731392" } } diff --git a/config.template.json b/config.template.json index 54dfdbe2..d0ba396d 100644 --- a/config.template.json +++ b/config.template.json @@ -116,5 +116,11 @@ "winnerRoleId": "1045422896740311070", "emotifiziererRoleId": "893179190709477410", "lootRoleAsseGuardRoleId": "1268706685753622529" + }, + + "emoji": { + "alarmEmojiId": "986292638204448838", + "sadHamsterEmojiId": "896110620108263424", + "trichterEmojiId": "986290070908731392" } } From 254b6942684ad7063ca7fcbe3531a8410bf7ef9f Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:15:18 +0100 Subject: [PATCH 02/17] Fix path --- src/service/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/command.ts b/src/service/command.ts index 4e58615c..98cc1d73 100644 --- a/src/service/command.ts +++ b/src/service/command.ts @@ -67,7 +67,7 @@ async function loadRawCommandModulesFromDirectory( continue; } - const filePath = path.join(context.path.commands, file); + const filePath = path.join(commandDir, file); const moduleUrl = new URL("file://"); moduleUrl.pathname = filePath; From bdcd395c971c7f0b763b68a591cefa7df36e9f0d Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:17:49 +0100 Subject: [PATCH 03/17] Support loading mod commands --- src/handler/commandHandler.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 68d2146b..92afa945 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -52,12 +52,17 @@ export const loadCommands = async (context: BotContext): Promise => { "mod", "normal", ]); - const loadedCommandNames = new Set(staticCommands.map(c => c.name)); + + // We also respect the modCommand flag, so we can load .hilfe and ~hilfe + const loadedCommandNames = new Set( + staticCommands.map(c => `${c.name}-${c.modCommand ?? false}`), + ); const dynamicCommands = []; for (const instance of availableCommands) { - if (loadedCommandNames.has(instance.name)) { - log.debug(`Command "${instance.name}" is already loaded, skipping`); + const loadedName = `${instance.name}-${instance.modCommand ?? false}`; + if (loadedCommandNames.has(loadedName)) { + log.debug(`Command "${loadedName}" is already loaded, skipping`); continue; } From d801cfc7da310f33031dd4790c775cd5697c1684 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:18:20 +0100 Subject: [PATCH 04/17] We only load normal commands, no need for check --- src/commands/hilfe.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/commands/hilfe.ts b/src/commands/hilfe.ts index 27c6d4a3..9a4cb58c 100644 --- a/src/commands/hilfe.ts +++ b/src/commands/hilfe.ts @@ -18,10 +18,6 @@ export default class HilfeCommand implements MessageCommand { const lines = []; const newCommands = await commandService.readAvailableCommands(context, ["normal"]); for (const command of newCommands) { - if (command.modCommand) { - continue; - } - // TODO: Hack to exclude faulenzerping and video download if ( "applicationCommand" in command && From 7b72a544563eb98e7c14617d5fe5d9c9b53d607f Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:18:45 +0100 Subject: [PATCH 05/17] As mod commands can have the same names, we need to differentiate --- src/handler/commandHandler.ts | 26 ++++++++++++++++---------- src/service/command.ts | 8 ++------ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 92afa945..4179c1d9 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -41,13 +41,15 @@ const allCommands: Command[] = []; const getApplicationCommands = () => allCommands.filter(c => "handleInteraction" in c); const getAutocompleteCommands = () => allCommands.filter(c => "autocomplete" in c); -const getMessageCommands = () => allCommands.filter(c => "handleMessage" in c); const getSpecialCommands = () => allCommands.filter(c => "handleSpecialMessage" in c); +const getMessageCommands = (modCommand: boolean) => + allCommands + .filter(c => modCommand === (c.modCommand ?? false)) + .filter(c => "handleMessage" in c); const latestSpecialCommandInvocations: Record = {}; export const loadCommands = async (context: BotContext): Promise => { - // TODO: This breaks hilfe command; we should distinguish between mod commands and normal commands const availableCommands = await commandService.readAvailableCommands(context, [ "mod", "normal", @@ -193,13 +195,15 @@ const hasPermissions = ( * was found or an error if the command would be a mod command but the * invoking user is not a mod */ -const commandMessageHandler = async ( + +async function commandMessageHandler( commandString: string, + isModCommand: boolean, message: ProcessableMessage, context: BotContext, -): Promise => { +): Promise { const lowerCommand = commandString.toLowerCase(); - const matchingCommand = getMessageCommands().find( + const matchingCommand = getMessageCommands(isModCommand).find( cmd => cmd.name.toLowerCase() === lowerCommand || cmd.aliases?.includes(lowerCommand), ); @@ -233,7 +237,7 @@ const commandMessageHandler = async ( content: `Tut mir leid, ${message.author}. Du hast nicht genügend Rechte um dieses Command zu verwenden, dafür gibt's erstmal mit dem Willkürhammer einen auf den Deckel.`, }), ]); -}; +} const isCooledDown = (command: SpecialCommand) => { const now = Date.now(); @@ -302,13 +306,15 @@ export const messageCommandHandler = async ( if (content.startsWith(plebPrefix) || content.startsWith(modPrefix)) { const splitContent = content.split(/\s+/); - const cmdString = content.startsWith(plebPrefix) - ? splitContent[0].slice(plebPrefix.length) - : splitContent[0].slice(modPrefix.length); + const isModCommand = content.startsWith(modPrefix); + + const cmdString = isModCommand + ? splitContent[0].slice(modPrefix.length) + : splitContent[0].slice(plebPrefix.length); if (cmdString) { try { - await commandMessageHandler(cmdString, message, context); + await commandMessageHandler(cmdString, isModCommand, message, context); } catch (err) { log.error(err, "Error while handling message command"); sentry.captureException(err); diff --git a/src/service/command.ts b/src/service/command.ts index 98cc1d73..2333b8f7 100644 --- a/src/service/command.ts +++ b/src/service/command.ts @@ -21,14 +21,11 @@ export async function readAvailableCommands( const modules = []; if (kinds.includes("mod")) { - const modCommands = await loadRawCommandModulesFromDirectory( - context, - context.path.modCommands, - ); + const modCommands = await loadRawCommandModulesFromDirectory(context.path.modCommands); modules.push(...modCommands); } if (kinds.includes("normal")) { - const commands = await loadRawCommandModulesFromDirectory(context, context.path.commands); + const commands = await loadRawCommandModulesFromDirectory(context.path.commands); modules.push(...commands); } @@ -52,7 +49,6 @@ type CommandModuleFile = { }; async function loadRawCommandModulesFromDirectory( - context: BotContext, commandDir: string, ): Promise { const commandFiles = await fs.readdir(commandDir); From 7cedfbee0ab2c4b9c4c118b396aba7064be01ca8 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:24:31 +0100 Subject: [PATCH 06/17] Move param around --- src/handler/commandHandler.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 4179c1d9..943bce70 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -197,8 +197,8 @@ const hasPermissions = ( */ async function commandMessageHandler( - commandString: string, isModCommand: boolean, + commandString: string, message: ProcessableMessage, context: BotContext, ): Promise { @@ -207,6 +207,10 @@ async function commandMessageHandler( cmd => cmd.name.toLowerCase() === lowerCommand || cmd.aliases?.includes(lowerCommand), ); + if (matchingCommand?.modCommand ?? false !== isModCommand) { + throw new Error("Somehow we got `command.modCommand !== isModCommand`"); + } + if ( context.roleGuard.hasBotDenyRole(message.member) && !context.channelGuard.isInBotSpam(message) @@ -298,7 +302,7 @@ export const messageCommandHandler = async ( return; } - // TODO: The Prefix is now completely irrelevant, since the commands itself define their permission. + // We need the prefix to differentiate between ~hilfe and .hilfe, which are different commands const plebPrefix = context.prefix.command; const modPrefix = context.prefix.modCommand; @@ -314,7 +318,7 @@ export const messageCommandHandler = async ( if (cmdString) { try { - await commandMessageHandler(cmdString, isModCommand, message, context); + await commandMessageHandler(isModCommand, cmdString, message, context); } catch (err) { log.error(err, "Error while handling message command"); sentry.captureException(err); From d0ef61eaf532996decf333378b2aafa3565ddd50 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:24:40 +0100 Subject: [PATCH 07/17] Check permission --- src/handler/commandHandler.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 943bce70..f46480cf 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -227,7 +227,12 @@ async function commandMessageHandler( const invoker = message.member; - if (hasPermissions(invoker, matchingCommand.requiredPermissions ?? [])) { + const isModCommandAndAllowed = isModCommand && context.roleGuard.isMod(invoker); + + if ( + isModCommandAndAllowed || + hasPermissions(invoker, matchingCommand.requiredPermissions ?? []) + ) { return await sentry.startSpan( { name: matchingCommand.name, op: "command.message" }, async () => await matchingCommand.handleMessage(message, context), From 892fc8f6165796d4dad7072194cb3d51a76fe993 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:28:04 +0100 Subject: [PATCH 08/17] Fix prefix --- src/commands/modcommands/hilfe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/modcommands/hilfe.ts b/src/commands/modcommands/hilfe.ts index c178ae03..3f171155 100644 --- a/src/commands/modcommands/hilfe.ts +++ b/src/commands/modcommands/hilfe.ts @@ -14,7 +14,7 @@ export default class ModHilfeCommand implements MessageCommand { description = "Listet alle mod-commands auf"; async handleMessage(message: ProcessableMessage, context: BotContext): Promise { - const prefix = context.prefix.command; + const prefix = context.prefix.modCommand; const lines = []; const newCommands = await commandService.readAvailableCommands(context, ["mod"]); From d18ceaaa8b2b81498dcc65c187a9a5b897228752 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:28:12 +0100 Subject: [PATCH 09/17] Fix preceence --- src/handler/commandHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index f46480cf..ef0d411b 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -207,7 +207,7 @@ async function commandMessageHandler( cmd => cmd.name.toLowerCase() === lowerCommand || cmd.aliases?.includes(lowerCommand), ); - if (matchingCommand?.modCommand ?? false !== isModCommand) { + if ((matchingCommand?.modCommand ?? false) !== isModCommand) { throw new Error("Somehow we got `command.modCommand !== isModCommand`"); } From 10b35875a69c7488a78d8d88acca1730d3651a4f Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:29:07 +0100 Subject: [PATCH 10/17] ban/unban are also application commands --- src/commands/modcommands/hilfe.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/commands/modcommands/hilfe.ts b/src/commands/modcommands/hilfe.ts index 3f171155..4bd074c8 100644 --- a/src/commands/modcommands/hilfe.ts +++ b/src/commands/modcommands/hilfe.ts @@ -1,5 +1,3 @@ -import { ContextMenuCommandBuilder } from "discord.js"; - import type { MessageCommand } from "#commands/command.ts"; import type { BotContext } from "#context.ts"; import type { ProcessableMessage } from "#service/command.ts"; @@ -23,14 +21,6 @@ export default class ModHilfeCommand implements MessageCommand { continue; } - // TODO: Hack to exclude faulenzerping and video download - if ( - "applicationCommand" in command && - command.applicationCommand instanceof ContextMenuCommandBuilder - ) { - continue; - } - const commandStr = prefix + command.name; lines.push( `${commandStr}: ${replacePrefixPlaceholders(command.description, context)}\n`, From 4aef3d8c296084ffb778d7b1140e2c46115df0c8 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:30:48 +0100 Subject: [PATCH 11/17] Fix skip of application commands --- src/commands/modcommands/hilfe.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/commands/modcommands/hilfe.ts b/src/commands/modcommands/hilfe.ts index 4bd074c8..391cdde0 100644 --- a/src/commands/modcommands/hilfe.ts +++ b/src/commands/modcommands/hilfe.ts @@ -17,10 +17,6 @@ export default class ModHilfeCommand implements MessageCommand { const lines = []; const newCommands = await commandService.readAvailableCommands(context, ["mod"]); for (const command of newCommands) { - if (!command.modCommand) { - continue; - } - const commandStr = prefix + command.name; lines.push( `${commandStr}: ${replacePrefixPlaceholders(command.description, context)}\n`, From 364ba7e775d6b5e5579424f0c08628441e88d515 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 02:33:13 +0100 Subject: [PATCH 12/17] Add flags regardless --- src/commands/modcommands/ban.ts | 1 + src/commands/modcommands/ghostwriter.ts | 2 ++ src/commands/modcommands/unban.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/src/commands/modcommands/ban.ts b/src/commands/modcommands/ban.ts index 2cce6018..eff63111 100644 --- a/src/commands/modcommands/ban.ts +++ b/src/commands/modcommands/ban.ts @@ -16,6 +16,7 @@ import * as banService from "#service/ban.ts"; import { formatDuration } from "#utils/dateUtils.ts"; export default class BanCommand implements ApplicationCommand, MessageCommand { + modCommand = true; // needed if invoked via text, not via slash name = "ban"; description = "Joa, bannt halt einen ne?"; requiredPermissions: readonly PermissionsString[] = ["BanMembers"]; diff --git a/src/commands/modcommands/ghostwriter.ts b/src/commands/modcommands/ghostwriter.ts index 9acc7523..f7bdc105 100644 --- a/src/commands/modcommands/ghostwriter.ts +++ b/src/commands/modcommands/ghostwriter.ts @@ -10,9 +10,11 @@ import type { ApplicationCommand } from "#commands/command.ts"; import type { BotContext } from "#context.ts"; export default class GhostwriterCommand implements ApplicationCommand { + modCommand = true; name = "gw"; description = "Goethe sein Vater"; requiredPermissions: readonly PermissionsString[] = ["BanMembers"]; + lastBlame: Date | null = null; get applicationCommand() { return new SlashCommandBuilder() diff --git a/src/commands/modcommands/unban.ts b/src/commands/modcommands/unban.ts index 06f19223..8cf197e1 100644 --- a/src/commands/modcommands/unban.ts +++ b/src/commands/modcommands/unban.ts @@ -12,6 +12,7 @@ import type { BotContext } from "#context.ts"; import * as banService from "#service/ban.ts"; export default class UnbanCommand implements ApplicationCommand, MessageCommand { + modCommand = true; // needed if invoked via text, not via slash name = "unban"; description = "Joa, unbannt halt einen ne?"; requiredPermissions: readonly PermissionsString[] = ["BanMembers"]; From 80d4fd98c4c820563f8d7df1b6a6418c5823d13b Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 19:02:59 +0100 Subject: [PATCH 13/17] Use implication if isModCommand -> isModUser --- src/handler/commandHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index ef0d411b..1c453774 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -227,10 +227,10 @@ async function commandMessageHandler( const invoker = message.member; - const isModCommandAndAllowed = isModCommand && context.roleGuard.isMod(invoker); + const isModCommandAndAllowed = !isModCommand || context.roleGuard.isMod(invoker); if ( - isModCommandAndAllowed || + isModCommandAndAllowed && hasPermissions(invoker, matchingCommand.requiredPermissions ?? []) ) { return await sentry.startSpan( From cc1af3f4a8d4668d228be8e9acf4f4c8e6c18326 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 19:03:21 +0100 Subject: [PATCH 14/17] hilfe -> modhilfe --- src/commands/modcommands/{hilfe.ts => modhilfe.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/commands/modcommands/{hilfe.ts => modhilfe.ts} (98%) diff --git a/src/commands/modcommands/hilfe.ts b/src/commands/modcommands/modhilfe.ts similarity index 98% rename from src/commands/modcommands/hilfe.ts rename to src/commands/modcommands/modhilfe.ts index 391cdde0..a6c302fd 100644 --- a/src/commands/modcommands/hilfe.ts +++ b/src/commands/modcommands/modhilfe.ts @@ -8,7 +8,7 @@ import * as commandService from "#service/command.ts"; export default class ModHilfeCommand implements MessageCommand { modCommand = true; - name = "hilfe"; + name = "modhilfe"; description = "Listet alle mod-commands auf"; async handleMessage(message: ProcessableMessage, context: BotContext): Promise { From 53091cabf8c691b8cac974664b9106666ce6656f Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 19:07:28 +0100 Subject: [PATCH 15/17] Remove distinction --- src/commands/hilfe.ts | 6 +++++- src/commands/modcommands/modhilfe.ts | 6 +++++- src/handler/commandHandler.ts | 15 ++++----------- src/service/command.ts | 21 +++++---------------- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/commands/hilfe.ts b/src/commands/hilfe.ts index 9a4cb58c..ea4ac125 100644 --- a/src/commands/hilfe.ts +++ b/src/commands/hilfe.ts @@ -16,8 +16,12 @@ export default class HilfeCommand implements MessageCommand { const prefix = context.prefix.command; const lines = []; - const newCommands = await commandService.readAvailableCommands(context, ["normal"]); + const newCommands = await commandService.readAvailableCommands(context); for (const command of newCommands) { + if (command.modCommand) { + continue; + } + // TODO: Hack to exclude faulenzerping and video download if ( "applicationCommand" in command && diff --git a/src/commands/modcommands/modhilfe.ts b/src/commands/modcommands/modhilfe.ts index a6c302fd..9b13d99c 100644 --- a/src/commands/modcommands/modhilfe.ts +++ b/src/commands/modcommands/modhilfe.ts @@ -15,8 +15,12 @@ export default class ModHilfeCommand implements MessageCommand { const prefix = context.prefix.modCommand; const lines = []; - const newCommands = await commandService.readAvailableCommands(context, ["mod"]); + const newCommands = await commandService.readAvailableCommands(context); for (const command of newCommands) { + if (!command.modCommand) { + continue; + } + const commandStr = prefix + command.name; lines.push( `${commandStr}: ${replacePrefixPlaceholders(command.description, context)}\n`, diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 1c453774..7d239458 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -50,21 +50,14 @@ const getMessageCommands = (modCommand: boolean) => const latestSpecialCommandInvocations: Record = {}; export const loadCommands = async (context: BotContext): Promise => { - const availableCommands = await commandService.readAvailableCommands(context, [ - "mod", - "normal", - ]); + const availableCommands = await commandService.readAvailableCommands(context); - // We also respect the modCommand flag, so we can load .hilfe and ~hilfe - const loadedCommandNames = new Set( - staticCommands.map(c => `${c.name}-${c.modCommand ?? false}`), - ); + const loadedCommandNames = new Set(staticCommands.map(c => c.name)); const dynamicCommands = []; for (const instance of availableCommands) { - const loadedName = `${instance.name}-${instance.modCommand ?? false}`; - if (loadedCommandNames.has(loadedName)) { - log.debug(`Command "${loadedName}" is already loaded, skipping`); + if (loadedCommandNames.has(instance.name)) { + log.debug(`Command "${instance.name}" is already loaded, skipping`); continue; } diff --git a/src/service/command.ts b/src/service/command.ts index 2333b8f7..92be3bfa 100644 --- a/src/service/command.ts +++ b/src/service/command.ts @@ -12,22 +12,11 @@ import log from "#log"; const commandExtensions = [".ts", ".js"]; const ignoredExtensions = [".spec.ts", ".test.ts", ".d.ts", ".test.js", ".spec.js"]; -export type CommandKind = "mod" | "normal"; - -export async function readAvailableCommands( - context: BotContext, - kinds: readonly CommandKind[], -): Promise { - const modules = []; - - if (kinds.includes("mod")) { - const modCommands = await loadRawCommandModulesFromDirectory(context.path.modCommands); - modules.push(...modCommands); - } - if (kinds.includes("normal")) { - const commands = await loadRawCommandModulesFromDirectory(context.path.commands); - modules.push(...commands); - } +export async function readAvailableCommands(context: BotContext): Promise { + const modules = [ + ...(await loadRawCommandModulesFromDirectory(context.path.modCommands)), + ...(await loadRawCommandModulesFromDirectory(context.path.commands)), + ]; const res = []; for (const { module } of modules) { From 3a75bc521e117728d05665ee153cb10c1d02c15e Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 19:23:42 +0100 Subject: [PATCH 16/17] Remove param --- src/handler/commandHandler.ts | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 7d239458..7872ebbc 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -42,10 +42,7 @@ const allCommands: Command[] = []; const getApplicationCommands = () => allCommands.filter(c => "handleInteraction" in c); const getAutocompleteCommands = () => allCommands.filter(c => "autocomplete" in c); const getSpecialCommands = () => allCommands.filter(c => "handleSpecialMessage" in c); -const getMessageCommands = (modCommand: boolean) => - allCommands - .filter(c => modCommand === (c.modCommand ?? false)) - .filter(c => "handleMessage" in c); +const getMessageCommands = () => allCommands.filter(c => "handleMessage" in c); const latestSpecialCommandInvocations: Record = {}; @@ -190,18 +187,17 @@ const hasPermissions = ( */ async function commandMessageHandler( - isModCommand: boolean, commandString: string, message: ProcessableMessage, context: BotContext, ): Promise { const lowerCommand = commandString.toLowerCase(); - const matchingCommand = getMessageCommands(isModCommand).find( + const command = getMessageCommands().find( cmd => cmd.name.toLowerCase() === lowerCommand || cmd.aliases?.includes(lowerCommand), ); - if ((matchingCommand?.modCommand ?? false) !== isModCommand) { - throw new Error("Somehow we got `command.modCommand !== isModCommand`"); + if (!command) { + return; } if ( @@ -214,21 +210,14 @@ async function commandMessageHandler( return; } - if (!matchingCommand) { - return; - } - const invoker = message.member; - const isModCommandAndAllowed = !isModCommand || context.roleGuard.isMod(invoker); + const isNormalCommandOrUserIsMod = !command.modCommand || context.roleGuard.isMod(invoker); - if ( - isModCommandAndAllowed && - hasPermissions(invoker, matchingCommand.requiredPermissions ?? []) - ) { + if (isNormalCommandOrUserIsMod && hasPermissions(invoker, command.requiredPermissions ?? [])) { return await sentry.startSpan( - { name: matchingCommand.name, op: "command.message" }, - async () => await matchingCommand.handleMessage(message, context), + { name: command.name, op: "command.message" }, + async () => await command.handleMessage(message, context), ); } @@ -308,15 +297,13 @@ export const messageCommandHandler = async ( if (content.startsWith(plebPrefix) || content.startsWith(modPrefix)) { const splitContent = content.split(/\s+/); - const isModCommand = content.startsWith(modPrefix); - - const cmdString = isModCommand + const cmdString = content.startsWith(modPrefix) ? splitContent[0].slice(modPrefix.length) : splitContent[0].slice(plebPrefix.length); if (cmdString) { try { - await commandMessageHandler(isModCommand, cmdString, message, context); + await commandMessageHandler(cmdString, message, context); } catch (err) { log.error(err, "Error while handling message command"); sentry.captureException(err); From b9591f2d5900657bc23ebbd2c7337dbc0d2132b9 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sun, 1 Feb 2026 19:26:48 +0100 Subject: [PATCH 17/17] Remove outdated comment --- src/handler/commandHandler.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/handler/commandHandler.ts b/src/handler/commandHandler.ts index 7872ebbc..e9aa78f5 100644 --- a/src/handler/commandHandler.ts +++ b/src/handler/commandHandler.ts @@ -289,7 +289,6 @@ export const messageCommandHandler = async ( return; } - // We need the prefix to differentiate between ~hilfe and .hilfe, which are different commands const plebPrefix = context.prefix.command; const modPrefix = context.prefix.modCommand; @@ -297,9 +296,9 @@ export const messageCommandHandler = async ( if (content.startsWith(plebPrefix) || content.startsWith(modPrefix)) { const splitContent = content.split(/\s+/); - const cmdString = content.startsWith(modPrefix) - ? splitContent[0].slice(modPrefix.length) - : splitContent[0].slice(plebPrefix.length); + const cmdString = content.startsWith(plebPrefix) + ? splitContent[0].slice(plebPrefix.length) + : splitContent[0].slice(modPrefix.length); if (cmdString) { try {