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
129
130
131
132
133
134
|
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;
console.dir(message);
console.dir(appSlashPerms);
console.dir(userSlashPerms);
console.dir(event);
console.dir(command);
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;
}
|