/[sudobot]/branches/7.x/src/commands/moderation/BanCommand.ts
ViewVC logotype

Annotation of /branches/7.x/src/commands/moderation/BanCommand.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: 8246 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 { formatDistanceToNow } from "date-fns";
21     import {
22     ChatInputCommandInteraction,
23     GuildMember,
24     PermissionsBitField,
25     SlashCommandBuilder,
26     User,
27     escapeMarkdown
28     } from "discord.js";
29     import Command, { ArgumentType, BasicCommandContext, CommandMessage, CommandReturn, ValidationRule } from "../../core/Command";
30     import { stringToTimeInterval } from "../../utils/datetime";
31     import { logError } from "../../utils/logger";
32     import { createModerationEmbed } from "../../utils/utils";
33    
34     export default class BanCommand extends Command {
35     public readonly name = "ban";
36     public readonly validationRules: ValidationRule[] = [
37     {
38     types: [ArgumentType.User],
39     entity: {
40     notNull: true
41     },
42     errors: {
43     required: "You must specify a user to ban!",
44     "type:invalid": "You have specified an invalid user mention or ID.",
45     "entity:null": "The given user does not exist!"
46     }
47     },
48     {
49     types: [ArgumentType.TimeInterval, ArgumentType.StringRest],
50     optional: true,
51     errors: {
52     "time:range": "The message deletion range must be a time interval from 0 second to 604800 seconds (7 days).",
53     "type:invalid":
54     "You have specified an invalid argument. The system expected you to provide a ban reason or the message deletion range here."
55     },
56     time: {
57     min: 0,
58     max: 604800,
59     unit: "s"
60     },
61     string: {
62     maxLength: 3999
63     }
64     },
65     {
66     types: [ArgumentType.StringRest],
67     optional: true,
68     errors: {
69     "type:invalid": "You have specified an invalid ban reason."
70     },
71     string: {
72     maxLength: 3999
73     }
74     }
75     ];
76     public readonly permissions = [PermissionsBitField.Flags.BanMembers];
77    
78     public readonly description = "Bans a user.";
79     public readonly detailedDescription =
80     "This command can ban users in the server or outside of the server. If the user is not in the server, you must specify their ID to ban them.";
81     public readonly argumentSyntaxes = ["<UserID|UserMention> [Reason]", "<UserID|UserMention> [MessageDeletionTime] [Reason]"];
82    
83     public readonly botRequiredPermissions = [PermissionsBitField.Flags.BanMembers];
84    
85     public readonly slashCommandBuilder = new SlashCommandBuilder()
86     .addUserOption(option => option.setName("user").setDescription("The user").setRequired(true))
87     .addStringOption(option => option.setName("reason").setDescription("The reason for banning this user"))
88     .addStringOption(option =>
89     option.setName("deletion_timeframe").setDescription("The message deletion timeframe (must be in range 0-604800s)")
90     )
91     .addBooleanOption(option =>
92     option
93     .setName("silent")
94     .setDescription("Specify if the system should not notify the user about this action. Defaults to false")
95     );
96    
97     async execute(message: CommandMessage, context: BasicCommandContext): Promise<CommandReturn> {
98     if (message instanceof ChatInputCommandInteraction) await message.deferReply();
99    
100     const user: User = context.isLegacy ? context.parsedArgs[0] : context.options.getUser("user", true);
101     let deleteMessageSeconds = !context.isLegacy
102     ? undefined
103     : typeof context.parsedArgs[1] === "number"
104     ? context.parsedArgs[1]
105     : undefined;
106     const reason = !context.isLegacy
107     ? context.options.getString("reason") ?? undefined
108     : typeof context.parsedArgs[1] === "string"
109     ? context.parsedArgs[1]
110     : context.parsedArgs[2];
111     let durationMs: undefined | number = undefined;
112    
113     ifContextIsNotLegacyForDeleteTimeframe: if (!context.isLegacy) {
114     const input = context.options.getString("deletion_timeframe");
115    
116     if (!input) break ifContextIsNotLegacyForDeleteTimeframe;
117    
118     const { result, error } = stringToTimeInterval(input);
119    
120     if (error) {
121     await this.deferredReply(message, {
122     content: `${this.emoji("error")} ${error} provided in the \`deletion_timeframe\` option`
123     });
124    
125     return;
126     }
127    
128     if (result < 0 || result > 604800) {
129     await this.deferredReply(
130     message,
131     `${this.emoji(
132     "error"
133     )} The message deletion range must be a time interval from 0 second to 604800 seconds (7 days).`
134     );
135     return;
136     }
137    
138     deleteMessageSeconds = result;
139     }
140    
141     ifContextIsNotLegacy: if (!context.isLegacy) {
142     const input = context.options.getString("duration");
143    
144     if (!input) break ifContextIsNotLegacy;
145    
146     const { result, error } = stringToTimeInterval(input, { milliseconds: true });
147    
148     if (error) {
149     await this.deferredReply(message, {
150     content: `${this.emoji("error")} ${error} provided in the \`duration\` option`
151     });
152    
153     return;
154     }
155    
156     durationMs = result;
157     }
158    
159     try {
160     const member = message.guild!.members.cache.get(user.id) ?? (await message.guild!.members.fetch(user.id));
161    
162     if (!(await this.client.permissionManager.shouldModerate(member, message.member! as GuildMember))) {
163     await this.error(message, "You don't have permission to ban this user!");
164     return;
165     }
166     } catch (e) {
167     logError(e);
168     }
169    
170     const id = await this.client.infractionManager.createUserBan(user, {
171     guild: message.guild!,
172     moderator: message.member!.user as User,
173     deleteMessageSeconds,
174     reason,
175     notifyUser: context.isLegacy ? true : !context.options.getBoolean("silent"),
176     sendLog: true,
177     duration: durationMs,
178     autoRemoveQueue: true
179     });
180    
181     if (!id) {
182     await this.error(message);
183     return;
184     }
185    
186     await this.deferredReply(
187     message,
188     {
189     embeds: [
190     await createModerationEmbed({
191     user,
192     moderator: message.member!.user as User,
193     actionDoneName: "banned",
194     description: `**${escapeMarkdown(user.tag)}** has been banned from this server.`,
195     fields: [
196     {
197     name: "Message Deletion",
198     value: deleteMessageSeconds
199     ? `Timeframe: ${formatDistanceToNow(
200     new Date(Date.now() - deleteMessageSeconds * 1000)
201     )}\nMessages in this timeframe by this user will be removed.`
202     : "*No message will be deleted*"
203     }
204     ],
205     id: `${id}`,
206     reason
207     })
208     ]
209     },
210     "auto"
211     );
212     }
213     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26