1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import type { BotCommand, CommandMessage, SlashMessage } from '#lib';
import { CommandHandler, CommandHandlerEvents, type Category, type CommandHandlerOptions } from 'discord-akairo';
import { GuildMember, PermissionResolvable, type Collection, type Message, type PermissionsString } from 'discord.js';
import { CommandHandlerEvent } from '../../utils/Constants.js';
export type CustomCommandHandlerOptions = CommandHandlerOptions;
export interface BotCommandHandlerEvents extends CommandHandlerEvents {
commandBlocked: [message: CommandMessage, command: BotCommand, reason: string];
commandBreakout: [message: CommandMessage, command: BotCommand, /* no util */ breakMessage: Message];
commandCancelled: [message: CommandMessage, command: BotCommand, /* no util */ retryMessage?: Message];
commandFinished: [message: CommandMessage, command: BotCommand, args: any, returnValue: any];
commandInvalid: [message: CommandMessage, command: BotCommand];
commandLocked: [message: CommandMessage, command: BotCommand];
commandStarted: [message: CommandMessage, command: BotCommand, args: any];
cooldown: [message: CommandMessage | SlashMessage, command: BotCommand, remaining: number];
error: [error: Error, message: /* no util */ Message, command?: BotCommand];
inPrompt: [message: /* no util */ Message];
load: [command: BotCommand, isReload: boolean];
messageBlocked: [message: /* no util */ Message | CommandMessage | SlashMessage, reason: string];
messageInvalid: [message: CommandMessage];
missingPermissions: [
message: CommandMessage,
command: BotCommand,
type: 'client' | 'user',
// fix: this is jank
missing: (PermissionsString | '[[UnsupportedChannel]]')[]
];
remove: [command: BotCommand];
slashBlocked: [message: SlashMessage, command: BotCommand, reason: string];
slashError: [error: Error, message: SlashMessage, command: BotCommand];
slashFinished: [message: SlashMessage, command: BotCommand, args: any, returnValue: any];
slashMissingPermissions: [
message: SlashMessage,
command: BotCommand,
type: 'client' | 'user',
// fix: this is jank
missing: (PermissionsString | '[[UnsupportedChannel]]')[]
];
slashStarted: [message: SlashMessage, command: BotCommand, args: any];
}
export class BotCommandHandler extends CommandHandler {
public declare modules: Collection<string, BotCommand>;
public declare categories: Collection<string, Category<string, BotCommand>>;
//! this is a simplified version of the original
public override async runPermissionChecks(
message: Message | SlashMessage,
command: BotCommand,
slash: boolean = false
): Promise<boolean> {
const event = slash ? CommandHandlerEvent.SlashMissingPermissions : CommandHandlerEvent.MissingPermissions;
const appSlashPerms = slash ? (message as SlashMessage).interaction.appPermissions : null;
const userSlashPerms = slash ? (message as SlashMessage).interaction.memberPermissions : null;
const noPerms = message.channel == null || (message.channel.isThread() && message.channel.parent == null);
if (message.inGuild()) {
if (noPerms && command.clientCheckChannel && appSlashPerms == null) {
this.emit(event, message, command, 'client', ['[[UnsupportedChannel]]']);
return true;
}
if (message.channel?.isDMBased()) return false;
const missing = command.clientCheckChannel
? (appSlashPerms ?? message.channel?.permissionsFor(message.guild.members.me!))?.missing(command.clientPermissions)
: message.guild?.members.me?.permissions.missing(command.clientPermissions);
if (missing?.length) {
this.emit(event, message, command, 'client', missing);
return true;
}
}
if (command.userPermissions) {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const ignorer = command.ignorePermissions || this.ignorePermissions;
const isIgnored = Array.isArray(ignorer)
? ignorer.includes(message.author.id)
: typeof ignorer === 'function'
? ignorer(message, command)
: message.author.id === ignorer;
if (!isIgnored) {
if (message.inGuild()) {
if (noPerms && command.userCheckChannel && userSlashPerms == null) {
this.emit(event, message, command, 'user', ['[[UnsupportedChannel]]']);
return true;
}
if (message.channel?.isDMBased()) return false;
const missing = command.userCheckChannel
? (userSlashPerms ?? message.channel?.permissionsFor(message.author))?.missing(command.userPermissions)
: message.member?.permissions.missing(command.userPermissions);
if (missing?.length) {
this.emit(event, message, command, 'user', missing);
return true;
}
}
}
}
return false;
}
}
export interface BotCommandHandler extends CommandHandler {
findCommand(name: string): BotCommand;
}
export function permissionCheck(
message: CommandMessage | SlashMessage,
check: GuildMember,
perms: PermissionResolvable,
useChannel: boolean
): boolean {
if (message.inGuild()) {
if (!message.channel || message.channel.isDMBased()) return true;
const missing = useChannel ? message.channel.permissionsFor(check)?.missing(perms) : check.permissions.missing(perms);
if (missing?.length) return false;
}
return true;
}
|