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

Contents of /branches/6.x/src/commands/settings/HelpCommand.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show 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 /**
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