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

Annotation of /branches/7.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: 12953 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 {
21     ActionRowBuilder,
22     ButtonBuilder,
23     ButtonStyle,
24     Collection,
25     EmbedBuilder,
26     PermissionResolvable,
27     SlashCommandBuilder,
28     escapeCodeBlock,
29     escapeInlineCode
30     } from "discord.js";
31     import Command, { ArgumentType, BasicCommandContext, CommandMessage, CommandReturn, ValidationRule } from "../../core/Command";
32     import { GatewayEventListener } from "../../decorators/GatewayEventListener";
33     import Pagination from "../../utils/Pagination";
34     import { DOCS_URL, GITHUB_URL, WEBSITE_URL } from "../../utils/links";
35     import { log } from "../../utils/logger";
36     import { forceGetPermissionNames, getComponentEmojiResolvable } from "../../utils/utils";
37    
38     export interface CommandInfo {
39     name: string;
40     aliases: string[];
41     group: string;
42     description?: string;
43     detailedDscription?: string;
44     systemAdminOnly: boolean;
45     beta: boolean;
46     argumentSyntaxes?: string[];
47     botRequiredPermissions?: PermissionResolvable[];
48     availableOptions?: Record<string, string>;
49     since: string;
50     supportsInteractions: boolean;
51     supportsLegacy: boolean;
52     }
53    
54     export default class HelpCommand extends Command {
55     public readonly name = "help";
56     public readonly validationRules: ValidationRule[] = [
57     {
58     types: [ArgumentType.String],
59     name: "command",
60     optional: true
61     },
62     {
63     types: [ArgumentType.String],
64     name: "subcommand",
65     optional: true
66     }
67     ];
68     public readonly permissions = [];
69    
70     public readonly description = "Shows this help information.";
71     public readonly detailedDescription =
72     "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.";
73    
74     public readonly argumentSyntaxes = ["[command]"];
75    
76     public readonly commandInformation = new Collection<string, string[]>();
77     public readonly slashCommandBuilder = new SlashCommandBuilder()
78     .addStringOption(option => option.setName("command").setDescription("Shows help for this command"))
79     .addStringOption(option => option.setName("subcommand").setDescription("Shows help for this subcommand"));
80    
81     @GatewayEventListener("ready")
82     async onReady() {
83     log("Attempting to read and extract meta info from all the loaded commands...");
84    
85     for await (const command of this.client.commands.values()) {
86     if (command.name.includes("__")) continue;
87     const commands = this.commandInformation.get(command.group) ?? [];
88    
89     if (commands.includes(command.name)) {
90     continue;
91     }
92    
93     commands.push(command.name);
94     this.commandInformation.set(command.group, commands);
95     }
96    
97     for (const group of this.commandInformation.keys()) {
98     this.commandInformation.get(group)?.sort((a, b) => a.localeCompare(b, ["en-US"]));
99     }
100    
101     log("Successfully read metadata of " + this.commandInformation.size + " commands");
102     }
103    
104     async execute(message: CommandMessage, context: BasicCommandContext): Promise<CommandReturn> {
105     await this.deferIfInteraction(message);
106     const commandName = context.isLegacy ? context.parsedNamedArgs.command : context.options.getString("command");
107     const subcommand = context.isLegacy ? context.parsedNamedArgs.subcommand : context.options.getString("subcommand");
108    
109     const config = this.client.configManager.config[message.guildId!];
110    
111     if (!config) {
112     await this.error(
113     message,
114     "This server isn't configured. Please ask a system administrator to configure this server."
115     );
116     return;
117     }
118    
119     if (!commandName) {
120     const pagination = new Pagination([...this.commandInformation.entries()], {
121     channelId: message.channelId!,
122     client: this.client,
123     guildId: message.guildId!,
124     limit: 1,
125     timeout: 200_000,
126     userId: message.member!.user.id,
127     embedBuilder: ({ currentPage, maxPages, data: [[group, commandNames]] }) => {
128     let description: string = `Run \`${config.prefix}help <commandName>\` to get help about a specific command.\n\`<...>\` means required argument, \`[...]\` means optional argument.\n\n`;
129     description += `**${group}**\n\`${commandNames.join("`, `")}\`\n\n`;
130    
131     return new EmbedBuilder({
132     author: {
133     name: "Help",
134     iconURL: this.client.user?.displayAvatarURL() ?? undefined
135     },
136     color: 0x007bff,
137     description,
138     footer: {
139     text: `Page ${currentPage} of ${maxPages}`
140     }
141     }).setTimestamp();
142     },
143     messageOptions: {
144     components: [
145     new ActionRowBuilder<ButtonBuilder>().addComponents(
146     new ButtonBuilder()
147     .setStyle(ButtonStyle.Link)
148     .setEmoji("📘")
149     .setURL(DOCS_URL)
150     .setLabel("Documentation"),
151     new ButtonBuilder()
152     .setStyle(ButtonStyle.Link)
153     .setEmoji(getComponentEmojiResolvable(this.client, "github") ?? "☄️")
154     .setURL(GITHUB_URL)
155     .setLabel("GitHub"),
156     new ButtonBuilder().setStyle(ButtonStyle.Link).setEmoji("🌍").setURL(WEBSITE_URL).setLabel("Website")
157     )
158     ]
159     }
160     });
161    
162     const reply = await this.deferredReply(message, await pagination.getMessageOptions(1));
163     await pagination.start(reply);
164     } else {
165     const name = subcommand ? `${commandName} ${subcommand}` : commandName;
166     const command = this.client.commands.get(subcommand ? `${commandName}__${subcommand}` : commandName);
167    
168     if (!command) {
169     await this.error(
170     message,
171     subcommand
172     ? `No command \`${commandName}\` or no subcommand \`${subcommand}\` exists.`
173     : `No command named \`${escapeInlineCode(escapeCodeBlock(commandName))}\` exists!`
174     );
175     return;
176     }
177    
178     const options = command.availableOptions ? Object.entries(command.availableOptions) : [];
179    
180     await this.deferredReply(message, {
181     embeds: [
182     new EmbedBuilder({
183     title: `${config.prefix}${name}${command.beta ? ` [BETA]` : ""}`,
184     color: 0x007bff,
185     fields: [
186     {
187     name: "Name",
188     value: `\`${subcommand ? name : command.name}\``,
189     inline: true
190     },
191     {
192     name: "Group",
193     value: `\`${command.group}\``,
194     inline: true
195     },
196     ...(command.aliases.length > 0
197     ? [
198     {
199     name: "Aliases",
200     value: command.aliases.map(c => `\`${c}\``).join("\n")
201     }
202     ]
203     : []),
204     {
205     name: "Description",
206     value: command.detailedDescription ?? command.description ?? "*No description available*"
207     },
208     {
209     name: "Syntax",
210     value: `\`\`\`\n${
211     command.argumentSyntaxes
212     ? command.argumentSyntaxes.map(s => `${config.prefix}${name} ${s}`).join("\n")
213     : `${config.prefix}${name}`
214     }\n\`\`\``
215     },
216     ...(command.subcommands.length > 0
217     ? [
218     {
219     name: "Subcommands",
220     value: `Run \`${config.prefix}help ${
221     command.name
222     } <subcommand>\` to see information about specific subcommands.\n\n* ${command.subcommands
223     .map(s => `\`${s}\``)
224     .join("\n* ")}`
225     }
226     ]
227     : []),
228     ...(command.botRequiredPermissions.length > 0
229     ? [
230     {
231     name: "Required Bot Permissions",
232     value: "`" + forceGetPermissionNames(command.botRequiredPermissions).join("`\n`") + "`",
233     inline: true
234     }
235     ]
236     : []),
237     ...(command.permissions.length > 0
238     ? [
239     {
240     name: "Required User Permissions",
241     value:
242     "`" +
243     forceGetPermissionNames(command.permissions).join(
244     `\`\n${command.permissionMode === "or" ? "or, " : ""}\``
245     ) +
246     "`",
247     inline: true
248     }
249     ]
250     : []),
251     ...(options.length > 0
252     ? [
253     {
254     name: "Options",
255     value: options.map(([name, description]) => `* \`${name}\` - ${description}`).join("\n")
256     }
257     ]
258     : []),
259     {
260     name: "Mode",
261     value: `${this.emoji(command.supportsLegacy ? "check" : "error")} Legacy\n${this.emoji(
262     command.supportsInteractions ? "check" : "error"
263     )} Interaction-based`
264     },
265     {
266     name: "Other Information",
267     value: `Available since \`${command.since}\`.\n${
268     command.beta ? "This command is under beta testing.\n" : ""
269     }${
270     command.systemAdminOnly
271     ? "This command can only be used by the System Administrators of the bot.\n"
272     : ""
273     }`,
274     inline: true
275     }
276     ]
277     }).setTimestamp()
278     ]
279     });
280     }
281     }
282     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26