Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/commands/hilfe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ 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;
Expand Down
1 change: 1 addition & 0 deletions src/commands/modcommands/ban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down
2 changes: 2 additions & 0 deletions src/commands/modcommands/ghostwriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -10,27 +8,19 @@ 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<void> {
const prefix = context.prefix.command;
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;
}

// 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`,
Expand Down
1 change: 1 addition & 0 deletions src/commands/modcommands/unban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down
35 changes: 17 additions & 18 deletions src/handler/commandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,14 @@ 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 = () => allCommands.filter(c => "handleMessage" in c);

const latestSpecialCommandInvocations: Record<string, number> = {};

export const loadCommands = async (context: BotContext): Promise<void> => {
// TODO: This breaks hilfe command; we should distinguish between mod commands and normal commands
const availableCommands = await commandService.readAvailableCommands(context, [
"mod",
"normal",
]);
const availableCommands = await commandService.readAvailableCommands(context);

const loadedCommandNames = new Set(staticCommands.map(c => c.name));

const dynamicCommands = [];
Expand Down Expand Up @@ -188,16 +185,21 @@ 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,
message: ProcessableMessage,
context: BotContext,
): Promise<unknown> => {
): Promise<unknown> {
const lowerCommand = commandString.toLowerCase();
const matchingCommand = getMessageCommands().find(
const command = getMessageCommands().find(
cmd => cmd.name.toLowerCase() === lowerCommand || cmd.aliases?.includes(lowerCommand),
);

if (!command) {
return;
}

if (
context.roleGuard.hasBotDenyRole(message.member) &&
!context.channelGuard.isInBotSpam(message)
Expand All @@ -208,16 +210,14 @@ const commandMessageHandler = async (
return;
}

if (!matchingCommand) {
return;
}

const invoker = message.member;

if (hasPermissions(invoker, matchingCommand.requiredPermissions ?? [])) {
const isNormalCommandOrUserIsMod = !command.modCommand || context.roleGuard.isMod(invoker);

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),
);
}

Expand All @@ -228,7 +228,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();
Expand Down Expand Up @@ -289,7 +289,6 @@ export const messageCommandHandler = async (
return;
}

// TODO: The Prefix is now completely irrelevant, since the commands itself define their permission.
const plebPrefix = context.prefix.command;
const modPrefix = context.prefix.modCommand;

Expand Down
27 changes: 6 additions & 21 deletions src/service/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +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<Command[]> {
const modules = [];

if (kinds.includes("mod")) {
const modCommands = await loadRawCommandModulesFromDirectory(
context,
context.path.modCommands,
);
modules.push(...modCommands);
}
if (kinds.includes("normal")) {
const commands = await loadRawCommandModulesFromDirectory(context, context.path.commands);
modules.push(...commands);
}
export async function readAvailableCommands(context: BotContext): Promise<Command[]> {
const modules = [
...(await loadRawCommandModulesFromDirectory(context.path.modCommands)),
...(await loadRawCommandModulesFromDirectory(context.path.commands)),
];

const res = [];
for (const { module } of modules) {
Expand All @@ -52,7 +38,6 @@ type CommandModuleFile = {
};

async function loadRawCommandModulesFromDirectory(
context: BotContext,
commandDir: string,
): Promise<CommandModuleFile[]> {
const commandFiles = await fs.readdir(commandDir);
Expand All @@ -67,7 +52,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;
Expand Down