blob: 12bfc3e7ad644aa8c00c5cfd0540e2721969cecb [file] [log] [blame]
TheCodedProf21c08592022-09-13 14:14:43 -04001import { CommandInteraction, GuildMember, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
PineaFana00db1b2023-01-02 15:32:54 +00002import type { 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,
PineaFana34d04b2023-01-03 22:05:42 +000054 null,
Skyler Grey75ea9172022-08-06 10:22:23 +010055 "ICONS.NOTIFY." + (notify ? "ON" : "OFF"),
56 notify
57 )
pineafan73a7c4a2022-07-24 10:38:04 +010058 .addReasonButton(reason ?? "")
pineafan63fc5e22022-08-04 22:04:10 +010059 .send(reason !== null);
60 reason = reason ?? "";
Skyler Greyad002172022-08-16 18:48:26 +010061 if (confirmation.cancelled) timedOut = true;
62 else if (confirmation.success) success = true;
63 else if (confirmation.newReason) reason = confirmation.newReason;
64 else if (confirmation.components) {
pineafan63fc5e22022-08-04 22:04:10 +010065 notify = confirmation.components.notify.active;
pineafan02ba0232022-07-24 22:16:15 +010066 }
pineafan73a7c4a2022-07-24 10:38:04 +010067 }
Skyler Greyad002172022-08-16 18:48:26 +010068 if (timedOut) return;
pineafan377794f2022-04-18 19:01:01 +010069 if (confirmation.success) {
70 let dmd = false;
pineafan63fc5e22022-08-04 22:04:10 +010071 const config = await client.database.guilds.read(interaction.guild.id);
pineafan8b4b17f2022-02-27 20:42:52 +000072 try {
pineafan02ba0232022-07-24 22:16:15 +010073 if (notify) {
Skyler Grey11236ba2022-08-08 21:13:33 +010074 await (interaction.options.getMember("user") as GuildMember).send({
Skyler Grey75ea9172022-08-06 10:22:23 +010075 embeds: [
76 new EmojiEmbed()
77 .setEmoji("PUNISH.BAN.RED")
78 .setTitle("Softbanned")
79 .setDescription(
80 `You have been softbanned from ${interaction.guild.name}` +
81 (reason ? ` for:\n> ${reason}` : ".")
82 )
83 .setStatus("Danger")
pineafan377794f2022-04-18 19:01:01 +010084 ],
Skyler Grey75ea9172022-08-06 10:22:23 +010085 components: [
TheCodedProf21c08592022-09-13 14:14:43 -040086 new ActionRowBuilder().addComponents(
Skyler Grey75ea9172022-08-06 10:22:23 +010087 config.moderation.ban.text
88 ? [
TheCodedProf21c08592022-09-13 14:14:43 -040089 new ButtonBuilder()
90 .setStyle(ButtonStyle.Link)
Skyler Grey75ea9172022-08-06 10:22:23 +010091 .setLabel(config.moderation.ban.text)
92 .setURL(config.moderation.ban.link)
93 ]
94 : []
95 )
96 ]
pineafan63fc5e22022-08-04 22:04:10 +010097 });
98 dmd = true;
pineafan8b4b17f2022-02-27 20:42:52 +000099 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100100 } catch {
101 dmd = false;
102 }
103 const member = interaction.options.getMember("user") as GuildMember;
pineafan8b4b17f2022-02-27 20:42:52 +0000104 try {
pineafan4edb7762022-06-26 19:21:04 +0100105 await member.ban({
pineafan8b4b17f2022-02-27 20:42:52 +0000106 days: Number(interaction.options.getInteger("delete") ?? 0),
pineafan73a7c4a2022-07-24 10:38:04 +0100107 reason: reason
pineafan5d1908e2022-02-28 21:34:47 +0000108 });
pineafan4edb7762022-06-26 19:21:04 +0100109 await interaction.guild.members.unban(member, "Softban");
pineafan8b4b17f2022-02-27 20:42:52 +0000110 } catch {
Skyler Grey75ea9172022-08-06 10:22:23 +0100111 await interaction.editReply({
112 embeds: [
113 new EmojiEmbed()
114 .setEmoji("PUNISH.BAN.RED")
115 .setTitle("Softban")
Skyler Grey11236ba2022-08-08 21:13:33 +0100116 .setDescription("Something went wrong and the user was not softbanned")
Skyler Grey75ea9172022-08-06 10:22:23 +0100117 .setStatus("Danger")
118 ],
119 components: []
120 });
pineafan8b4b17f2022-02-27 20:42:52 +0000121 }
Skyler Grey11236ba2022-08-08 21:13:33 +0100122 await client.database.history.create("softban", interaction.guild.id, member.user, reason);
Skyler Grey75ea9172022-08-06 10:22:23 +0100123 const failed = !dmd && notify;
124 await interaction.editReply({
125 embeds: [
126 new EmojiEmbed()
127 .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
128 .setTitle("Softban")
Skyler Grey11236ba2022-08-08 21:13:33 +0100129 .setDescription("The member was softbanned" + (failed ? ", but could not be notified" : ""))
Skyler Grey75ea9172022-08-06 10:22:23 +0100130 .setStatus(failed ? "Warning" : "Success")
131 ],
132 components: []
133 });
pineafan8b4b17f2022-02-27 20:42:52 +0000134 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +0100135 await interaction.editReply({
136 embeds: [
137 new EmojiEmbed()
138 .setEmoji("PUNISH.BAN.GREEN")
139 .setTitle("Softban")
140 .setDescription("No changes were made")
141 .setStatus("Success")
142 ],
143 components: []
144 });
pineafan8b4b17f2022-02-27 20:42:52 +0000145 }
pineafan63fc5e22022-08-04 22:04:10 +0100146};
pineafan4f164f32022-02-26 22:07:12 +0000147
pineafanbd02b4a2022-08-05 22:01:38 +0100148const check = (interaction: CommandInteraction) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100149 const member = interaction.member as GuildMember;
150 const me = interaction.guild.me!;
151 const apply = interaction.options.getMember("user") as GuildMember;
pineafan3a02ea32022-08-11 21:35:04 +0100152 if (member === null || me === null || apply === null) throw new Error("That member is not in the server");
pineafan62ce1922022-08-25 20:34:45 +0100153 const memberPos = member.roles.cache.size > 1 ? member.roles.highest.position : 0;
154 const mePos = me.roles.cache.size > 1 ? me.roles.highest.position : 0;
155 const applyPos = apply.roles.cache.size > 1 ? apply.roles.highest.position : 0;
pineafanc1c18792022-08-03 21:41:36 +0100156 // Do not allow softbanning the owner
pineafan3a02ea32022-08-11 21:35:04 +0100157 if (member.id === interaction.guild.ownerId) throw new Error("You cannot softban the owner of the server");
pineafan8b4b17f2022-02-27 20:42:52 +0000158 // Check if Nucleus can ban the member
pineafan3a02ea32022-08-11 21:35:04 +0100159 if (!(mePos > applyPos)) throw new Error("I do not have a role higher than that member");
pineafan8b4b17f2022-02-27 20:42:52 +0000160 // Check if Nucleus has permission to ban
pineafan3a02ea32022-08-11 21:35:04 +0100161 if (!me.permissions.has("BAN_MEMBERS")) throw new Error("I do not have the *Ban Members* permission");
pineafan8b4b17f2022-02-27 20:42:52 +0000162 // Do not allow softbanning Nucleus
pineafan3a02ea32022-08-11 21:35:04 +0100163 if (member.id === me.id) throw new Error("I cannot softban myself");
pineafanc1c18792022-08-03 21:41:36 +0100164 // Allow the owner to softban anyone
pineafan63fc5e22022-08-04 22:04:10 +0100165 if (member.id === interaction.guild.ownerId) return true;
pineafan8b4b17f2022-02-27 20:42:52 +0000166 // Check if the user has ban_members permission
pineafan3a02ea32022-08-11 21:35:04 +0100167 if (!member.permissions.has("BAN_MEMBERS")) throw new Error("You do not have the *Ban Members* permission");
pineafan8b4b17f2022-02-27 20:42:52 +0000168 // Check if the user is below on the role list
pineafan3a02ea32022-08-11 21:35:04 +0100169 if (!(memberPos > applyPos)) throw new Error("You do not have a role higher than that member");
pineafan8b4b17f2022-02-27 20:42:52 +0000170 // Allow softban
pineafan63fc5e22022-08-04 22:04:10 +0100171 return true;
172};
pineafan4f164f32022-02-26 22:07:12 +0000173
Skyler Grey75ea9172022-08-06 10:22:23 +0100174export { command, callback, check };