/[sudobot]/branches/5.x/src/commands/settings/HelpCommand.ts
ViewVC logotype

Annotation of /branches/5.x/src/commands/settings/HelpCommand.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (hide annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 12709 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 rakinar2 577 /**
2     * This file is part of SudoBot.
3     *
4     * Copyright (C) 2021-2023 OSN Developers.
5     *
6     * SudoBot is free software; you can redistribute it and/or modify it
7     * under the terms of the GNU Affero General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * SudoBot is distributed in the hope that it will be useful, but
12     * WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU Affero General Public License for more details.
15     *
16     * You should have received a copy of the GNU Affero General Public License
17     * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18     */
19    
20     import { Collection, EmbedBuilder, PermissionResolvable, SlashCommandBuilder, escapeCodeBlock, escapeInlineCode } from "discord.js";
21     import Command, { ArgumentType, BasicCommandContext, CommandMessage, CommandReturn, ValidationRule } from "../../core/Command";
22     import { GatewayEventListener } from "../../decorators/GatewayEventListener";
23     import Pagination from "../../utils/Pagination";
24     import { log } from "../../utils/logger";
25     import { forceGetPermissionNames } from "../../utils/utils";
26    
27     export interface CommandInfo {
28     name: string;
29     aliases: string[];
30     group: string;
31     description?: string;
32     detailedDscription?: string;
33     systemAdminOnly: boolean;
34     beta: boolean;
35     argumentSyntaxes?: string[];
36     botRequiredPermissions?: PermissionResolvable[];
37     availableOptions?: Record<string, string>;
38     since: string;
39     supportsInteractions: boolean;
40     supportsLegacy: boolean;
41     }
42    
43     export default class HelpCommand extends Command {
44     public readonly name = "help";
45     public readonly validationRules: ValidationRule[] = [
46     {
47     types: [ArgumentType.String],
48     name: "command",
49     optional: true
50     },
51     {
52     types: [ArgumentType.String],
53     name: "subcommand",
54     optional: true
55     }
56     ];
57     public readonly permissions = [];
58    
59     public readonly description = "Shows this help information.";
60     public readonly detailedDescription =
61     "Shows documentation about the bot's commands. You can even get information about individual commands by running `help <command>` where `<command>` is the command name.";
62    
63     public readonly argumentSyntaxes = ["[command]"];
64    
65     public readonly commandInformation = new Collection<string, CommandInfo>();
66     public readonly slashCommandBuilder = new SlashCommandBuilder()
67     .addStringOption(option => option.setName("command").setDescription("Shows help for this command"))
68     .addStringOption(option => option.setName("subcommand").setDescription("Shows help for this subcommand"));
69    
70     @GatewayEventListener("ready")
71     async onReady() {
72     log("Attempting to read and extract meta info from all the loaded commands...");
73    
74     for await (const command of this.client.commands.values()) {
75     if (command.name.includes("__")) continue;
76     if (this.commandInformation.has(command.name)) continue;
77    
78     this.commandInformation.set(command.name, {
79     name: command.name,
80     aliases: command.aliases,
81     group: command.group,
82     description: command.description,
83     detailedDscription: command.detailedDescription,
84     systemAdminOnly: command.systemAdminOnly,
85     beta: command.beta,
86     argumentSyntaxes: command.argumentSyntaxes,
87     botRequiredPermissions: command.botRequiredPermissions,
88     availableOptions: command.availableOptions,
89     since: command.since,
90     supportsInteractions: command.supportsInteractions,
91     supportsLegacy: command.supportsLegacy
92     });
93     }
94    
95     this.commandInformation.sort((a, b) => a.name.localeCompare(b.name, ["en-US"]));
96     log("Successfully read metadata of " + this.commandInformation.size + " commands");
97     }
98    
99     async execute(message: CommandMessage, context: BasicCommandContext): Promise<CommandReturn> {
100     await this.deferIfInteraction(message);
101     const commandName = context.isLegacy ? context.parsedNamedArgs.command : context.options.getString("command");
102     const subcommand = context.isLegacy ? context.parsedNamedArgs.subcommand : context.options.getString("subcommand");
103    
104     const config = this.client.configManager.config[message.guildId!];
105    
106     if (!config) {
107     await this.error(
108     message,
109     "This server isn't configured. Please ask a system administrator to configure this server."
110     );
111     return;
112     }
113    
114     if (!commandName) {
115     const pagination = new Pagination([...this.commandInformation.values()], {
116     channelId: message.channelId!,
117     client: this.client,
118     guildId: message.guildId!,
119     limit: 20,
120     timeout: 200_000,
121     userId: message.member!.user.id,
122     embedBuilder({ currentPage, maxPages, data }) {
123     let description: string = `Run \`${config.prefix}help <commandName>\` to get help about a specific command.\n\`<...>\` means required argument, \`[...]\` means optional argument.\n\n`;
124    
125     for (const commandInfo of data) {
126     description += `**${commandInfo.name}**\n`;
127     description += `${commandInfo.description ?? "*No description is available for this command.*"}\n`;
128    
129     if (commandInfo.systemAdminOnly) {
130     description += ":warning: This command can only be used by bot system administrators.\n";
131     }
132    
133     description += "\n";
134     }
135    
136     return new EmbedBuilder({
137     author: {
138     name: "Help",
139     iconURL: this.client.user?.displayAvatarURL() ?? undefined
140     },
141     color: 0x007bff,
142     description,
143     footer: {
144     text: `Page ${currentPage} of ${maxPages}`
145     }
146     }).setTimestamp();
147     }
148     });
149    
150     const reply = await this.deferredReply(message, await pagination.getMessageOptions(1));
151     await pagination.start(reply);
152     } else {
153     const name = subcommand ? `${commandName} ${subcommand}` : commandName;
154     const command = this.client.commands.get(subcommand ? `${commandName}__${subcommand}` : commandName);
155    
156     if (!command) {
157     await this.error(
158     message,
159     subcommand
160     ? `No command \`${commandName}\` or no subcommand \`${subcommand}\` exists.`
161     : `No command named \`${escapeInlineCode(escapeCodeBlock(commandName))}\` exists!`
162     );
163     return;
164     }
165    
166     const options = command.availableOptions ? Object.entries(command.availableOptions) : [];
167    
168     await this.deferredReply(message, {
169     embeds: [
170     new EmbedBuilder({
171     title: `${config.prefix}${name}${command.beta ? ` [BETA]` : ""}`,
172     color: 0x007bff,
173     fields: [
174     {
175     name: "Name",
176     value: `\`${subcommand ? name : command.name}\``,
177     inline: true
178     },
179     {
180     name: "Group",
181     value: `\`${command.group}\``,
182     inline: true
183     },
184     ...(command.aliases.length > 0
185     ? [
186     {
187     name: "Aliases",
188     value: command.aliases.map(c => `\`${c}\``).join("\n")
189     }
190     ]
191     : []),
192     {
193     name: "Description",
194     value: command.detailedDescription ?? command.description ?? "*No description available*"
195     },
196     {
197     name: "Syntax",
198     value: `\`\`\`\n${
199     command.argumentSyntaxes
200     ? command.argumentSyntaxes.map(s => `${config.prefix}${name} ${s}`).join("\n")
201     : `${config.prefix}${name}`
202     }\n\`\`\``
203     },
204     ...(command.subcommands.length > 0
205     ? [
206     {
207     name: "Subcommands",
208     value: `Run \`${config.prefix}help ${
209     command.name
210     } <subcommand>\` to see information about specific subcommands.\n\n* ${command.subcommands
211     .map(s => `\`${s}\``)
212     .join("\n* ")}`
213     }
214     ]
215     : []),
216     ...(command.botRequiredPermissions.length > 0
217     ? [
218     {
219     name: "Required Bot Permissions",
220     value: "`" + forceGetPermissionNames(command.botRequiredPermissions).join("`\n`") + "`",
221     inline: true
222     }
223     ]
224     : []),
225     ...(command.permissions.length > 0
226     ? [
227     {
228     name: "Required User Permissions",
229     value:
230     "`" +
231     forceGetPermissionNames(command.permissions).join(
232     `\`\n${command.permissionMode === "or" ? "or, " : ""}\``
233     ) +
234     "`",
235     inline: true
236     }
237     ]
238     : []),
239     ...(options.length > 0
240     ? [
241     {
242     name: "Options",
243     value: options.map(([name, description]) => `* \`${name}\` - ${description}`).join("\n")
244     }
245     ]
246     : []),
247     {
248     name: "Mode",
249     value: `${this.emoji(command.supportsLegacy ? "check" : "error")} Legacy\n${this.emoji(
250     command.supportsInteractions ? "check" : "error"
251     )} Interaction-based`
252     },
253     {
254     name: "Other Information",
255     value: `Available since \`${command.since}\`.\n${
256     command.beta ? "This command is under beta testing.\n" : ""
257     }${
258     command.systemAdminOnly
259     ? "This command can only be used by the System Administrators of the bot.\n"
260     : ""
261     }`,
262     inline: true
263     }
264     ]
265     }).setTimestamp()
266     ]
267     });
268     }
269     }
270     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26