blob: 13cfa89d89643183426fbd2b118cfa1628761cd3 [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
Skyler Grey75ea9172022-08-06 10:22:23 +01002import Discord, {
3 CommandInteraction,
4 MessageActionRow,
5 MessageButton,
6 TextInputComponent
7} from "discord.js";
pineafan0bc04162022-07-25 17:22:26 +01008import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
9import getEmojiByName from "../../utils/getEmojiByName.js";
10import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
11import { WrappedCheck } from "jshaiku";
12import client from "../../utils/client.js";
13import { modalInteractionCollector } from "../../utils/dualCollector.js";
14import confirmationMessage from "../../utils/confirmationMessage.js";
15import keyValueList from "../../utils/generateKeyValueList.js";
16
17const command = (builder: SlashCommandSubcommandBuilder) =>
18 builder
pineafan63fc5e22022-08-04 22:04:10 +010019 .setName("commands")
Skyler Grey75ea9172022-08-06 10:22:23 +010020 .setDescription(
21 "Links and text shown to a user after a moderator action is performed"
22 )
23 .addRoleOption((o) =>
24 o
25 .setName("role")
26 .setDescription("The role given when a member is muted")
27 );
pineafan0bc04162022-07-25 17:22:26 +010028
Skyler Grey75ea9172022-08-06 10:22:23 +010029const callback = async (
30 interaction: CommandInteraction
31): Promise<void | unknown> => {
32 await interaction.reply({
33 embeds: LoadingEmbed,
34 ephemeral: true,
35 fetchReply: true
36 });
pineafan0bc04162022-07-25 17:22:26 +010037 let m;
38 let clicked = "";
39 if (interaction.options.getRole("role")) {
pineafan63fc5e22022-08-04 22:04:10 +010040 const confirmation = await new confirmationMessage(interaction)
pineafan0bc04162022-07-25 17:22:26 +010041 .setEmoji("GUILD.ROLES.DELETE")
42 .setTitle("Moderation Commands")
Skyler Grey75ea9172022-08-06 10:22:23 +010043 .setDescription(
44 keyValueList({
45 role: `<@&${interaction.options.getRole("role").id}>`
46 })
47 )
pineafan0bc04162022-07-25 17:22:26 +010048 .setColor("Danger")
pineafan63fc5e22022-08-04 22:04:10 +010049 .send(true);
Skyler Grey75ea9172022-08-06 10:22:23 +010050 if (confirmation.cancelled)
51 return await interaction.editReply({
52 embeds: [
53 new EmojiEmbed()
54 .setTitle("Moderation Commands")
55 .setDescription("No changes were made")
56 .setStatus("Success")
57 .setEmoji("GUILD.ROLES.CREATE")
58 ]
59 });
pineafan0bc04162022-07-25 17:22:26 +010060 if (confirmation.success) {
Skyler Grey75ea9172022-08-06 10:22:23 +010061 await client.database.guilds.write(interaction.guild.id, {
62 ["moderation.mute.role"]: interaction.options.getRole("role").id
63 });
pineafan0bc04162022-07-25 17:22:26 +010064 }
65 }
66 while (true) {
pineafan63fc5e22022-08-04 22:04:10 +010067 const config = await client.database.guilds.read(interaction.guild.id);
68 const moderation = config.getKey("moderation");
Skyler Grey75ea9172022-08-06 10:22:23 +010069 m = await interaction.editReply({
70 embeds: [
71 new EmojiEmbed()
72 .setTitle("Moderation Commands")
73 .setEmoji("PUNISH.BAN.GREEN")
74 .setStatus("Success")
75 .setDescription(
76 "These links are shown below the message sent in a user's DM when they are punished.\n\n" +
77 "**Mute Role:** " +
78 (moderation.mute.role
79 ? `<@&${moderation.mute.role}>`
80 : "*None set*")
81 )
82 ],
83 components: [
84 new MessageActionRow().addComponents([
85 new MessageButton()
86 .setLabel("Warn")
87 .setEmoji(getEmojiByName("PUNISH.WARN.YELLOW", "id"))
88 .setCustomId("warn")
89 .setStyle("SECONDARY"),
90 new MessageButton()
91 .setLabel("Mute")
92 .setEmoji(getEmojiByName("PUNISH.MUTE.YELLOW", "id"))
93 .setCustomId("mute")
94 .setStyle("SECONDARY"),
95 new MessageButton()
96 .setLabel("Nickname")
97 .setEmoji(getEmojiByName("PUNISH.NICKNAME.GREEN", "id"))
98 .setCustomId("nickname")
99 .setStyle("SECONDARY")
100 ]),
101 new MessageActionRow().addComponents([
102 new MessageButton()
103 .setLabel("Kick")
104 .setEmoji(getEmojiByName("PUNISH.KICK.RED", "id"))
105 .setCustomId("kick")
106 .setStyle("SECONDARY"),
107 new MessageButton()
108 .setLabel("Softban")
109 .setEmoji(getEmojiByName("PUNISH.BAN.YELLOW", "id"))
110 .setCustomId("softban")
111 .setStyle("SECONDARY"),
112 new MessageButton()
113 .setLabel("Ban")
114 .setEmoji(getEmojiByName("PUNISH.BAN.RED", "id"))
115 .setCustomId("ban")
116 .setStyle("SECONDARY")
117 ]),
118 new MessageActionRow().addComponents([
119 new MessageButton()
120 .setLabel(
121 clicked === "clearMuteRole"
122 ? "Click again to confirm"
123 : "Clear mute role"
124 )
125 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
126 .setCustomId("clearMuteRole")
127 .setStyle("DANGER")
128 .setDisabled(!moderation.mute.role),
129 new MessageButton()
130 .setCustomId("timeout")
131 .setLabel(
132 "Mute timeout " +
133 (moderation.mute.timeout
134 ? "Enabled"
135 : "Disabled")
136 )
137 .setStyle(
138 moderation.mute.timeout ? "SUCCESS" : "DANGER"
139 )
140 .setEmoji(
141 getEmojiByName(
142 "CONTROL." +
143 (moderation.mute.timeout
144 ? "TICK"
145 : "CROSS"),
146 "id"
147 )
148 )
149 ])
150 ]
151 });
pineafan0bc04162022-07-25 17:22:26 +0100152 let i;
153 try {
154 i = await m.awaitMessageComponent({ time: 300000 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100155 } catch (e) {
156 return;
157 }
158 let chosen = moderation[i.customId] ?? { text: null, url: null };
pineafan0bc04162022-07-25 17:22:26 +0100159 if (i.component.customId === "clearMuteRole") {
pineafan63fc5e22022-08-04 22:04:10 +0100160 i.deferUpdate();
pineafan0bc04162022-07-25 17:22:26 +0100161 if (clicked === "clearMuteRole") {
Skyler Grey75ea9172022-08-06 10:22:23 +0100162 await client.database.guilds.write(interaction.guild.id, {
163 "moderation.mute.role": null
164 });
165 } else {
166 clicked = "clearMuteRole";
167 }
pineafan63fc5e22022-08-04 22:04:10 +0100168 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100169 } else {
170 clicked = "";
171 }
pineafan0bc04162022-07-25 17:22:26 +0100172 if (i.component.customId === "timeout") {
pineafan63fc5e22022-08-04 22:04:10 +0100173 await i.deferUpdate();
Skyler Grey75ea9172022-08-06 10:22:23 +0100174 await client.database.guilds.write(interaction.guild.id, {
175 "moderation.mute.timeout": !moderation.mute.timeout
176 });
pineafan63fc5e22022-08-04 22:04:10 +0100177 continue;
pineafan0bc04162022-07-25 17:22:26 +0100178 } else if (i.customId) {
Skyler Grey75ea9172022-08-06 10:22:23 +0100179 await i.showModal(
180 new Discord.Modal()
181 .setCustomId("modal")
182 .setTitle(`Options for ${i.customId}`)
183 .addComponents(
184 new MessageActionRow<TextInputComponent>().addComponents(
185 new TextInputComponent()
186 .setCustomId("name")
187 .setLabel("Button text")
188 .setMaxLength(100)
189 .setRequired(false)
190 .setStyle("SHORT")
191 .setValue(chosen.text ?? "")
192 ),
193 new MessageActionRow<TextInputComponent>().addComponents(
194 new TextInputComponent()
195 .setCustomId("url")
196 .setLabel(
197 "URL - Type {id} to insert the user's ID"
198 )
199 .setMaxLength(2000)
200 .setRequired(false)
201 .setStyle("SHORT")
202 .setValue(chosen.link ?? "")
203 )
204 )
205 );
pineafan0bc04162022-07-25 17:22:26 +0100206 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100207 embeds: [
208 new EmojiEmbed()
209 .setTitle("Moderation Links")
210 .setDescription(
211 "Modal opened. If you can't see it, click back and try again."
212 )
213 .setStatus("Success")
214 .setEmoji("GUILD.TICKET.OPEN")
215 ],
216 components: [
217 new MessageActionRow().addComponents([
218 new MessageButton()
219 .setLabel("Back")
220 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
221 .setStyle("PRIMARY")
222 .setCustomId("back")
223 ])
224 ]
pineafan0bc04162022-07-25 17:22:26 +0100225 });
226 let out;
227 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100228 out = await modalInteractionCollector(
229 m,
230 (m) => m.channel.id === interaction.channel.id,
231 (_) => true
232 );
233 } catch (e) {
234 continue;
235 }
pineafan0bc04162022-07-25 17:22:26 +0100236 if (out.fields) {
pineafan63fc5e22022-08-04 22:04:10 +0100237 const buttonText = out.fields.getTextInputValue("name");
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 const buttonLink = out.fields
239 .getTextInputValue("url")
240 .replace(/{id}/gi, "{id}");
pineafan63fc5e22022-08-04 22:04:10 +0100241 const current = chosen;
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 if (
243 current.text !== buttonText ||
244 current.link !== buttonLink
245 ) {
pineafan0bc04162022-07-25 17:22:26 +0100246 chosen = { text: buttonText, link: buttonLink };
Skyler Grey75ea9172022-08-06 10:22:23 +0100247 await client.database.guilds.write(interaction.guild.id, {
248 ["moderation." + i.customId]: {
249 text: buttonText,
250 link: buttonLink
251 }
252 });
pineafan0bc04162022-07-25 17:22:26 +0100253 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100254 } else {
255 continue;
256 }
pineafan0bc04162022-07-25 17:22:26 +0100257 }
258 }
pineafan63fc5e22022-08-04 22:04:10 +0100259};
pineafan0bc04162022-07-25 17:22:26 +0100260
Skyler Grey75ea9172022-08-06 10:22:23 +0100261const check = (
262 interaction: CommandInteraction,
263 _defaultCheck: WrappedCheck
264) => {
265 const member = interaction.member as Discord.GuildMember;
266 if (!member.permissions.has("MANAGE_GUILD"))
267 throw "You must have the *Manage Server* permission to use this command";
pineafan0bc04162022-07-25 17:22:26 +0100268 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100269};
pineafan0bc04162022-07-25 17:22:26 +0100270
271export { command };
272export { callback };
Skyler Grey75ea9172022-08-06 10:22:23 +0100273export { check };