blob: bbbb24a1cac749dc22f56db3d7999d6457b03548 [file] [log] [blame]
PineaFan0d06edc2023-01-17 22:10:31 +00001import { LoadingEmbed } from "../../utils/defaults.js";
TheCodedProf267563a2023-01-21 17:00:57 -05002import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, Role, ButtonStyle, ButtonComponent, TextInputBuilder, Message } from "discord.js";
pineafan0bc04162022-07-25 17:22:26 +01003import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
4import getEmojiByName from "../../utils/getEmojiByName.js";
TheCodedProff86ba092023-01-27 17:10:07 -05005import type { SlashCommandSubcommandBuilder } from "discord.js";
pineafan0bc04162022-07-25 17:22:26 +01006import client from "../../utils/client.js";
7import { modalInteractionCollector } from "../../utils/dualCollector.js";
8import confirmationMessage from "../../utils/confirmationMessage.js";
9import keyValueList from "../../utils/generateKeyValueList.js";
10
11const command = (builder: SlashCommandSubcommandBuilder) =>
12 builder
pineafan63fc5e22022-08-04 22:04:10 +010013 .setName("commands")
Skyler Grey11236ba2022-08-08 21:13:33 +010014 .setDescription("Links and text shown to a user after a moderator action is performed")
15 .addRoleOption((o) => o.setName("role").setDescription("The role given when a member is muted"));
pineafan0bc04162022-07-25 17:22:26 +010016
pineafan3a02ea32022-08-11 21:35:04 +010017const callback = async (interaction: CommandInteraction): Promise<unknown> => {
Skyler Grey75ea9172022-08-06 10:22:23 +010018 await interaction.reply({
19 embeds: LoadingEmbed,
20 ephemeral: true,
21 fetchReply: true
22 });
TheCodedProf267563a2023-01-21 17:00:57 -050023 let m: Message;
pineafan0bc04162022-07-25 17:22:26 +010024 let clicked = "";
TheCodedProf21c08592022-09-13 14:14:43 -040025 if (interaction.options.get("role")) {
pineafan63fc5e22022-08-04 22:04:10 +010026 const confirmation = await new confirmationMessage(interaction)
pineafan0bc04162022-07-25 17:22:26 +010027 .setEmoji("GUILD.ROLES.DELETE")
28 .setTitle("Moderation Commands")
Skyler Grey75ea9172022-08-06 10:22:23 +010029 .setDescription(
30 keyValueList({
TheCodedProf21c08592022-09-13 14:14:43 -040031 role: `<@&${(interaction.options.get("role") as unknown as Role).id}>`
Skyler Grey75ea9172022-08-06 10:22:23 +010032 })
33 )
pineafan0bc04162022-07-25 17:22:26 +010034 .setColor("Danger")
pineafan63fc5e22022-08-04 22:04:10 +010035 .send(true);
pineafan62ce1922022-08-25 20:34:45 +010036 if (confirmation.cancelled) return
pineafan0bc04162022-07-25 17:22:26 +010037 if (confirmation.success) {
TheCodedProfd9636e82023-01-17 22:13:06 -050038 await client.database.guilds.write(interaction.guild!.id, {
TheCodedProf21c08592022-09-13 14:14:43 -040039 ["moderation.mute.role"]: (interaction.options.get("role") as unknown as Role).id
Skyler Grey75ea9172022-08-06 10:22:23 +010040 });
pineafan0bc04162022-07-25 17:22:26 +010041 }
42 }
Skyler Greyad002172022-08-16 18:48:26 +010043 let timedOut = false;
44 while (!timedOut) {
TheCodedProfd9636e82023-01-17 22:13:06 -050045 const config = await client.database.guilds.read(interaction.guild!.id);
PineaFan9b2ac4d2023-01-18 14:41:07 +000046 const moderation = config.moderation;
Skyler Grey75ea9172022-08-06 10:22:23 +010047 m = await interaction.editReply({
48 embeds: [
49 new EmojiEmbed()
50 .setTitle("Moderation Commands")
51 .setEmoji("PUNISH.BAN.GREEN")
52 .setStatus("Success")
53 .setDescription(
54 "These links are shown below the message sent in a user's DM when they are punished.\n\n" +
55 "**Mute Role:** " +
Skyler Grey11236ba2022-08-08 21:13:33 +010056 (moderation.mute.role ? `<@&${moderation.mute.role}>` : "*None set*")
Skyler Grey75ea9172022-08-06 10:22:23 +010057 )
58 ],
59 components: [
TheCodedProfd9636e82023-01-17 22:13:06 -050060 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -040061 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010062 .setLabel("Warn")
63 .setEmoji(getEmojiByName("PUNISH.WARN.YELLOW", "id"))
64 .setCustomId("warn")
TheCodedProf21c08592022-09-13 14:14:43 -040065 .setStyle(ButtonStyle.Secondary),
66 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010067 .setLabel("Mute")
68 .setEmoji(getEmojiByName("PUNISH.MUTE.YELLOW", "id"))
69 .setCustomId("mute")
TheCodedProf21c08592022-09-13 14:14:43 -040070 .setStyle(ButtonStyle.Secondary),
71 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010072 .setLabel("Nickname")
73 .setEmoji(getEmojiByName("PUNISH.NICKNAME.GREEN", "id"))
74 .setCustomId("nickname")
TheCodedProf21c08592022-09-13 14:14:43 -040075 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +010076 ]),
TheCodedProfd9636e82023-01-17 22:13:06 -050077 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -040078 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010079 .setLabel("Kick")
80 .setEmoji(getEmojiByName("PUNISH.KICK.RED", "id"))
81 .setCustomId("kick")
TheCodedProf21c08592022-09-13 14:14:43 -040082 .setStyle(ButtonStyle.Secondary),
83 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010084 .setLabel("Softban")
85 .setEmoji(getEmojiByName("PUNISH.BAN.YELLOW", "id"))
86 .setCustomId("softban")
TheCodedProf21c08592022-09-13 14:14:43 -040087 .setStyle(ButtonStyle.Secondary),
88 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +010089 .setLabel("Ban")
90 .setEmoji(getEmojiByName("PUNISH.BAN.RED", "id"))
91 .setCustomId("ban")
TheCodedProf21c08592022-09-13 14:14:43 -040092 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +010093 ]),
TheCodedProfd9636e82023-01-17 22:13:06 -050094 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -040095 new ButtonBuilder()
Skyler Grey11236ba2022-08-08 21:13:33 +010096 .setLabel(clicked === "clearMuteRole" ? "Click again to confirm" : "Clear mute role")
Skyler Grey75ea9172022-08-06 10:22:23 +010097 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
98 .setCustomId("clearMuteRole")
TheCodedProf21c08592022-09-13 14:14:43 -040099 .setStyle(ButtonStyle.Danger)
Skyler Grey75ea9172022-08-06 10:22:23 +0100100 .setDisabled(!moderation.mute.role),
TheCodedProf21c08592022-09-13 14:14:43 -0400101 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100102 .setCustomId("timeout")
Skyler Grey11236ba2022-08-08 21:13:33 +0100103 .setLabel("Mute timeout " + (moderation.mute.timeout ? "Enabled" : "Disabled"))
TheCodedProf21c08592022-09-13 14:14:43 -0400104 .setStyle(moderation.mute.timeout ? ButtonStyle.Success : ButtonStyle.Danger)
Skyler Grey11236ba2022-08-08 21:13:33 +0100105 .setEmoji(getEmojiByName("CONTROL." + (moderation.mute.timeout ? "TICK" : "CROSS"), "id"))
Skyler Grey75ea9172022-08-06 10:22:23 +0100106 ])
107 ]
108 });
pineafan0bc04162022-07-25 17:22:26 +0100109 let i;
110 try {
PineaFan0d06edc2023-01-17 22:10:31 +0000111 i = await m.awaitMessageComponent({
112 time: 300000,
TheCodedProf267563a2023-01-21 17:00:57 -0500113 filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id && i.message.id === m.id }
PineaFan0d06edc2023-01-17 22:10:31 +0000114 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100115 } catch (e) {
Skyler Greyad002172022-08-16 18:48:26 +0100116 timedOut = true;
117 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100118 }
TheCodedProfd9636e82023-01-17 22:13:06 -0500119 type modIDs = "mute" | "kick" | "ban" | "softban" | "warn" | "role";
PineaFan9b2ac4d2023-01-18 14:41:07 +0000120 let chosen = moderation[i.customId as modIDs];
TheCodedProfd9636e82023-01-17 22:13:06 -0500121 if ((i.component as ButtonComponent).customId === "clearMuteRole") {
TheCodedProf267563a2023-01-21 17:00:57 -0500122 await i.deferUpdate();
pineafan0bc04162022-07-25 17:22:26 +0100123 if (clicked === "clearMuteRole") {
TheCodedProfd9636e82023-01-17 22:13:06 -0500124 await client.database.guilds.write(interaction.guild!.id, {
Skyler Grey75ea9172022-08-06 10:22:23 +0100125 "moderation.mute.role": null
126 });
127 } else {
128 clicked = "clearMuteRole";
129 }
pineafan63fc5e22022-08-04 22:04:10 +0100130 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100131 } else {
132 clicked = "";
133 }
TheCodedProfd9636e82023-01-17 22:13:06 -0500134 if ((i.component as ButtonComponent).customId === "timeout") {
pineafan63fc5e22022-08-04 22:04:10 +0100135 await i.deferUpdate();
TheCodedProfd9636e82023-01-17 22:13:06 -0500136 await client.database.guilds.write(interaction.guild!.id, {
Skyler Grey75ea9172022-08-06 10:22:23 +0100137 "moderation.mute.timeout": !moderation.mute.timeout
138 });
pineafan63fc5e22022-08-04 22:04:10 +0100139 continue;
pineafan0bc04162022-07-25 17:22:26 +0100140 } else if (i.customId) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100141 await i.showModal(
TheCodedProfd9636e82023-01-17 22:13:06 -0500142 new Discord.ModalBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100143 .setCustomId("modal")
144 .setTitle(`Options for ${i.customId}`)
145 .addComponents(
TheCodedProfd9636e82023-01-17 22:13:06 -0500146 new ActionRowBuilder<TextInputBuilder>().addComponents(
147 new TextInputBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100148 .setCustomId("name")
149 .setLabel("Button text")
150 .setMaxLength(100)
151 .setRequired(false)
TheCodedProfd9636e82023-01-17 22:13:06 -0500152 .setStyle(Discord.TextInputStyle.Short)
Skyler Grey75ea9172022-08-06 10:22:23 +0100153 .setValue(chosen.text ?? "")
TheCodedProfd9636e82023-01-17 22:13:06 -0500154 ).toJSON(),
155 new ActionRowBuilder<TextInputBuilder>().addComponents(
156 new TextInputBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100157 .setCustomId("url")
Skyler Grey11236ba2022-08-08 21:13:33 +0100158 .setLabel("URL - Type {id} to insert the user's ID")
Skyler Grey75ea9172022-08-06 10:22:23 +0100159 .setMaxLength(2000)
160 .setRequired(false)
TheCodedProfd9636e82023-01-17 22:13:06 -0500161 .setStyle(Discord.TextInputStyle.Short)
Skyler Grey75ea9172022-08-06 10:22:23 +0100162 .setValue(chosen.link ?? "")
TheCodedProfd9636e82023-01-17 22:13:06 -0500163 ).toJSON()
Skyler Grey75ea9172022-08-06 10:22:23 +0100164 )
165 );
pineafan0bc04162022-07-25 17:22:26 +0100166 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100167 embeds: [
168 new EmojiEmbed()
169 .setTitle("Moderation Links")
Skyler Grey11236ba2022-08-08 21:13:33 +0100170 .setDescription("Modal opened. If you can't see it, click back and try again.")
Skyler Grey75ea9172022-08-06 10:22:23 +0100171 .setStatus("Success")
172 .setEmoji("GUILD.TICKET.OPEN")
173 ],
174 components: [
TheCodedProfd9636e82023-01-17 22:13:06 -0500175 new ActionRowBuilder<ButtonBuilder>().addComponents([
TheCodedProf21c08592022-09-13 14:14:43 -0400176 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100177 .setLabel("Back")
178 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400179 .setStyle(ButtonStyle.Primary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100180 .setCustomId("back")
181 ])
182 ]
pineafan0bc04162022-07-25 17:22:26 +0100183 });
PineaFan9b2ac4d2023-01-18 14:41:07 +0000184 let out: Discord.ModalSubmitInteraction | null;
pineafan0bc04162022-07-25 17:22:26 +0100185 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100186 out = await modalInteractionCollector(
187 m,
TheCodedProfd9636e82023-01-17 22:13:06 -0500188 (m) => m.channel!.id === interaction.channel!.id,
Skyler Grey75ea9172022-08-06 10:22:23 +0100189 (_) => true
PineaFan9b2ac4d2023-01-18 14:41:07 +0000190 ) as Discord.ModalSubmitInteraction | null;
Skyler Grey75ea9172022-08-06 10:22:23 +0100191 } catch (e) {
192 continue;
193 }
TheCodedProf4a6d5712023-01-19 15:54:40 -0500194 if (!out || out.isButton()) continue
PineaFan9b2ac4d2023-01-18 14:41:07 +0000195 const buttonText = out.fields.getTextInputValue("name");
196 const buttonLink = out.fields.getTextInputValue("url").replace(/{id}/gi, "{id}");
197 const current = chosen;
198 if (current.text !== buttonText || current.link !== buttonLink) {
199 chosen = { text: buttonText, link: buttonLink };
200 await client.database.guilds.write(interaction.guild!.id, {
201 ["moderation." + i.customId]: {
202 text: buttonText,
203 link: buttonLink
204 }
205 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100206 }
pineafan0bc04162022-07-25 17:22:26 +0100207 }
208 }
pineafan63fc5e22022-08-04 22:04:10 +0100209};
pineafan0bc04162022-07-25 17:22:26 +0100210
TheCodedProff86ba092023-01-27 17:10:07 -0500211const check = (interaction: CommandInteraction, _partial: boolean = false) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100212 const member = interaction.member as Discord.GuildMember;
PineaFan0d06edc2023-01-17 22:10:31 +0000213 if (!member.permissions.has("ManageGuild"))
214 return "You must have the *Manage Server* permission to use this command";
pineafan0bc04162022-07-25 17:22:26 +0100215 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100216};
pineafan0bc04162022-07-25 17:22:26 +0100217
218export { command };
219export { callback };
Skyler Grey75ea9172022-08-06 10:22:23 +0100220export { check };