blob: 463ec16ef4e6649694a7d207330cffef7ae2c1bf [file] [log] [blame]
Skyler Grey11236ba2022-08-08 21:13:33 +01001import { CommandInteraction, GuildMember, MessageActionRow, MessageButton } from "discord.js";
pineafan4f164f32022-02-26 22:07:12 +00002import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
pineafan8b4b17f2022-02-27 20:42:52 +00003import confirmationMessage from "../../utils/confirmationMessage.js";
pineafan4edb7762022-06-26 19:21:04 +01004import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan8b4b17f2022-02-27 20:42:52 +00005import keyValueList from "../../utils/generateKeyValueList.js";
pineafan6702cef2022-06-13 17:52:37 +01006import client from "../../utils/client.js";
7import addPlural from "../../utils/plurals.js";
pineafan4f164f32022-02-26 22:07:12 +00008
9const command = (builder: SlashCommandSubcommandBuilder) =>
10 builder
pineafan63fc5e22022-08-04 22:04:10 +010011 .setName("softban")
12 .setDescription("Kicks a user and deletes their messages")
Skyler Grey11236ba2022-08-08 21:13:33 +010013 .addUserOption((option) => option.setName("user").setDescription("The user to softban").setRequired(true))
Skyler Grey75ea9172022-08-06 10:22:23 +010014 .addIntegerOption((option) =>
15 option
16 .setName("delete")
17 .setDescription("The days of messages to delete | Default: 0")
18 .setMinValue(0)
19 .setMaxValue(7)
20 .setRequired(false)
21 );
pineafan4f164f32022-02-26 22:07:12 +000022
pineafan3a02ea32022-08-11 21:35:04 +010023const callback = async (interaction: CommandInteraction): Promise<unknown> => {
pineafan63fc5e22022-08-04 22:04:10 +010024 const { renderUser } = client.logger;
pineafan8b4b17f2022-02-27 20:42:52 +000025 // TODO:[Modals] Replace this with a modal
pineafan73a7c4a2022-07-24 10:38:04 +010026 let reason = null;
pineafan02ba0232022-07-24 22:16:15 +010027 let notify = true;
pineafan73a7c4a2022-07-24 10:38:04 +010028 let confirmation;
Skyler Greyad002172022-08-16 18:48:26 +010029 let timedOut = false;
30 let success = false;
31 while (!timedOut && !success) {
pineafan63fc5e22022-08-04 22:04:10 +010032 const confirmation = await new confirmationMessage(interaction)
pineafan73a7c4a2022-07-24 10:38:04 +010033 .setEmoji("PUNISH.BAN.RED")
34 .setTitle("Softban")
Skyler Grey75ea9172022-08-06 10:22:23 +010035 .setDescription(
36 keyValueList({
37 user: renderUser(interaction.options.getUser("user")),
Skyler Grey11236ba2022-08-08 21:13:33 +010038 reason: reason ? "\n> " + (reason ?? "").replaceAll("\n", "\n> ") : "*No reason provided*"
Skyler Grey75ea9172022-08-06 10:22:23 +010039 }) +
40 `The user **will${notify ? "" : " not"}** be notified\n` +
41 `${addPlural(
Skyler Grey11236ba2022-08-08 21:13:33 +010042 interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0,
Skyler Grey75ea9172022-08-06 10:22:23 +010043 "day"
44 )} of messages will be deleted\n\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +010045 `Are you sure you want to softban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`
Skyler Grey75ea9172022-08-06 10:22:23 +010046 )
pineafan73a7c4a2022-07-24 10:38:04 +010047 .setColor("Danger")
Skyler Grey75ea9172022-08-06 10:22:23 +010048 .addCustomBoolean(
49 "notify",
50 "Notify user",
51 false,
52 null,
53 null,
54 "ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
55 notify
56 )
pineafan73a7c4a2022-07-24 10:38:04 +010057 .addReasonButton(reason ?? "")
pineafan63fc5e22022-08-04 22:04:10 +010058 .send(reason !== null);
59 reason = reason ?? "";
Skyler Greyad002172022-08-16 18:48:26 +010060 if (confirmation.cancelled) timedOut = true;
61 else if (confirmation.success) success = true;
62 else if (confirmation.newReason) reason = confirmation.newReason;
63 else if (confirmation.components) {
pineafan63fc5e22022-08-04 22:04:10 +010064 notify = confirmation.components.notify.active;
pineafan02ba0232022-07-24 22:16:15 +010065 }
pineafan73a7c4a2022-07-24 10:38:04 +010066 }
Skyler Greyad002172022-08-16 18:48:26 +010067 if (timedOut) return;
pineafan377794f2022-04-18 19:01:01 +010068 if (confirmation.success) {
69 let dmd = false;
pineafan63fc5e22022-08-04 22:04:10 +010070 const config = await client.database.guilds.read(interaction.guild.id);
pineafan8b4b17f2022-02-27 20:42:52 +000071 try {
pineafan02ba0232022-07-24 22:16:15 +010072 if (notify) {
Skyler Grey11236ba2022-08-08 21:13:33 +010073 await (interaction.options.getMember("user") as GuildMember).send({
Skyler Grey75ea9172022-08-06 10:22:23 +010074 embeds: [
75 new EmojiEmbed()
76 .setEmoji("PUNISH.BAN.RED")
77 .setTitle("Softbanned")
78 .setDescription(
79 `You have been softbanned from ${interaction.guild.name}` +
80 (reason ? ` for:\n> ${reason}` : ".")
81 )
82 .setStatus("Danger")
pineafan377794f2022-04-18 19:01:01 +010083 ],
Skyler Grey75ea9172022-08-06 10:22:23 +010084 components: [
85 new MessageActionRow().addComponents(
86 config.moderation.ban.text
87 ? [
88 new MessageButton()
89 .setStyle("LINK")
90 .setLabel(config.moderation.ban.text)
91 .setURL(config.moderation.ban.link)
92 ]
93 : []
94 )
95 ]
pineafan63fc5e22022-08-04 22:04:10 +010096 });
97 dmd = true;
pineafan8b4b17f2022-02-27 20:42:52 +000098 }
Skyler Grey75ea9172022-08-06 10:22:23 +010099 } catch {
100 dmd = false;
101 }
102 const member = interaction.options.getMember("user") as GuildMember;
pineafan8b4b17f2022-02-27 20:42:52 +0000103 try {
pineafan4edb7762022-06-26 19:21:04 +0100104 await member.ban({
pineafan8b4b17f2022-02-27 20:42:52 +0000105 days: Number(interaction.options.getInteger("delete") ?? 0),
pineafan73a7c4a2022-07-24 10:38:04 +0100106 reason: reason
pineafan5d1908e2022-02-28 21:34:47 +0000107 });
pineafan4edb7762022-06-26 19:21:04 +0100108 await interaction.guild.members.unban(member, "Softban");
pineafan8b4b17f2022-02-27 20:42:52 +0000109 } catch {
Skyler Grey75ea9172022-08-06 10:22:23 +0100110 await interaction.editReply({
111 embeds: [
112 new EmojiEmbed()
113 .setEmoji("PUNISH.BAN.RED")
114 .setTitle("Softban")
Skyler Grey11236ba2022-08-08 21:13:33 +0100115 .setDescription("Something went wrong and the user was not softbanned")
Skyler Grey75ea9172022-08-06 10:22:23 +0100116 .setStatus("Danger")
117 ],
118 components: []
119 });
pineafan8b4b17f2022-02-27 20:42:52 +0000120 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100121 await client.database.history.create("softban", interaction.guild.id, member.user, reason);
Skyler Grey75ea9172022-08-06 10:22:23 +0100122 const failed = !dmd && notify;
123 await interaction.editReply({
124 embeds: [
125 new EmojiEmbed()
126 .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
127 .setTitle("Softban")
Skyler Grey11236ba2022-08-08 21:13:33 +0100128 .setDescription("The member was softbanned" + (failed ? ", but could not be notified" : ""))
Skyler Grey75ea9172022-08-06 10:22:23 +0100129 .setStatus(failed ? "Warning" : "Success")
130 ],
131 components: []
132 });
pineafan8b4b17f2022-02-27 20:42:52 +0000133 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +0100134 await interaction.editReply({
135 embeds: [
136 new EmojiEmbed()
137 .setEmoji("PUNISH.BAN.GREEN")
138 .setTitle("Softban")
139 .setDescription("No changes were made")
140 .setStatus("Success")
141 ],
142 components: []
143 });
pineafan8b4b17f2022-02-27 20:42:52 +0000144 }
pineafan63fc5e22022-08-04 22:04:10 +0100145};
pineafan4f164f32022-02-26 22:07:12 +0000146
pineafanbd02b4a2022-08-05 22:01:38 +0100147const check = (interaction: CommandInteraction) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100148 const member = interaction.member as GuildMember;
149 const me = interaction.guild.me!;
150 const apply = interaction.options.getMember("user") as GuildMember;
pineafan3a02ea32022-08-11 21:35:04 +0100151 if (member === null || me === null || apply === null) throw new Error("That member is not in the server");
pineafan63fc5e22022-08-04 22:04:10 +0100152 const memberPos = member.roles ? member.roles.highest.position : 0;
153 const mePos = me.roles ? me.roles.highest.position : 0;
154 const applyPos = apply.roles ? apply.roles.highest.position : 0;
pineafanc1c18792022-08-03 21:41:36 +0100155 // Do not allow softbanning the owner
pineafan3a02ea32022-08-11 21:35:04 +0100156 if (member.id === interaction.guild.ownerId) throw new Error("You cannot softban the owner of the server");
pineafan8b4b17f2022-02-27 20:42:52 +0000157 // Check if Nucleus can ban the member
pineafan3a02ea32022-08-11 21:35:04 +0100158 if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
pineafan8b4b17f2022-02-27 20:42:52 +0000159 // Check if Nucleus has permission to ban
pineafan3a02ea32022-08-11 21:35:04 +0100160 if (!me.permissions.has("BAN_MEMBERS")) throw new Error("I do not have the *Ban Members* permission");
pineafan8b4b17f2022-02-27 20:42:52 +0000161 // Do not allow softbanning Nucleus
pineafan3a02ea32022-08-11 21:35:04 +0100162 if (member.id === me.id) throw new Error("I cannot softban myself");
pineafanc1c18792022-08-03 21:41:36 +0100163 // Allow the owner to softban anyone
pineafan63fc5e22022-08-04 22:04:10 +0100164 if (member.id === interaction.guild.ownerId) return true;
pineafan8b4b17f2022-02-27 20:42:52 +0000165 // Check if the user has ban_members permission
pineafan3a02ea32022-08-11 21:35:04 +0100166 if (!member.permissions.has("BAN_MEMBERS")) throw new Error("You do not have the *Ban Members* permission");
pineafan8b4b17f2022-02-27 20:42:52 +0000167 // Check if the user is below on the role list
pineafan3a02ea32022-08-11 21:35:04 +0100168 if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member");
pineafan8b4b17f2022-02-27 20:42:52 +0000169 // Allow softban
pineafan63fc5e22022-08-04 22:04:10 +0100170 return true;
171};
pineafan4f164f32022-02-26 22:07:12 +0000172
Skyler Grey75ea9172022-08-06 10:22:23 +0100173export { command, callback, check };