blob: 68454e46f02e85c8d3e5f26b320d12a69c9eb4a8 [file] [log] [blame]
TheCodedProf8b3da212023-02-02 15:09:55 -05001import type Discord from "discord.js";
Skyler Greyda16adf2023-03-05 10:22:12 +00002import {
3 ActionRowBuilder,
TheCodedProf5b53a8c2023-02-03 15:40:26 -05004 AnySelectMenuInteraction,
5 APIMessageComponentEmoji,
6 ButtonBuilder,
7 ButtonInteraction,
8 ButtonStyle,
9 ChannelSelectMenuBuilder,
10 ChannelSelectMenuInteraction,
11 CommandInteraction,
TheCodedProf5b53a8c2023-02-03 15:40:26 -050012 Message,
TheCodedProf5b53a8c2023-02-03 15:40:26 -050013 ModalBuilder,
TheCodedProf5b53a8c2023-02-03 15:40:26 -050014 RoleSelectMenuBuilder,
15 RoleSelectMenuInteraction,
16 StringSelectMenuBuilder,
17 StringSelectMenuInteraction,
18 StringSelectMenuOptionBuilder,
19 TextInputBuilder,
20 TextInputStyle,
21 UserSelectMenuBuilder,
22 UserSelectMenuInteraction
23} from "discord.js";
TheCodedProf8b3da212023-02-02 15:09:55 -050024import type { SlashCommandSubcommandBuilder } from "discord.js";
25import { LoadingEmbed } from "../../utils/defaults.js";
26import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
27import client from "../../utils/client.js";
28import getEmojiByName from "../../utils/getEmojiByName.js";
TheCodedProf5b53a8c2023-02-03 15:40:26 -050029import { modalInteractionCollector } from "../../utils/dualCollector.js";
TheCodedProf1f675042023-02-16 17:01:29 -050030import listToAndMore from "../../utils/listToAndMore.js";
TheCodedProf35e73712023-03-10 17:35:35 -050031import _ from "lodash";
TheCodedProf8b3da212023-02-02 15:09:55 -050032
33const command = (builder: SlashCommandSubcommandBuilder) =>
34 builder.setName("automod").setDescription("Setting for automatic moderation features");
35
Skyler Greyda16adf2023-03-05 10:22:12 +000036const emojiFromBoolean = (bool: boolean, id?: string) =>
37 bool ? getEmojiByName("CONTROL.TICK", id) : getEmojiByName("CONTROL.CROSS", id);
TheCodedProf8b3da212023-02-02 15:09:55 -050038
Skyler Greyda16adf2023-03-05 10:22:12 +000039const toSelectMenu = async (
40 interaction: StringSelectMenuInteraction,
41 m: Message,
42 ids: string[],
43 type: "member" | "role" | "channel",
44 title: string
45): Promise<string[]> => {
46 const back = new ActionRowBuilder<ButtonBuilder>().addComponents(
47 new ButtonBuilder()
48 .setCustomId("back")
49 .setLabel("Back")
50 .setStyle(ButtonStyle.Secondary)
51 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
52 );
TheCodedProf486bca32023-02-02 16:49:44 -050053 let closed;
54 do {
Skyler Greyda16adf2023-03-05 10:22:12 +000055 let render: string[] = [];
TheCodedProf486bca32023-02-02 16:49:44 -050056 let mapped: string[] = [];
57 let menu: UserSelectMenuBuilder | RoleSelectMenuBuilder | ChannelSelectMenuBuilder;
Skyler Greyda16adf2023-03-05 10:22:12 +000058 switch (type) {
PineaFanb0d0c242023-02-05 10:59:45 +000059 case "member": {
TheCodedProf486bca32023-02-02 16:49:44 -050060 menu = new UserSelectMenuBuilder().setCustomId("user").setPlaceholder("Select users").setMaxValues(25);
Skyler Greyda16adf2023-03-05 10:22:12 +000061 mapped = await Promise.all(
62 ids.map(async (id) => {
63 return (await client.users.fetch(id).then((user) => user.tag)) || "Unknown User";
64 })
65 );
66 render = ids.map((id) => client.logger.renderUser(id));
TheCodedProf486bca32023-02-02 16:49:44 -050067 break;
PineaFanb0d0c242023-02-05 10:59:45 +000068 }
69 case "role": {
TheCodedProf486bca32023-02-02 16:49:44 -050070 menu = new RoleSelectMenuBuilder().setCustomId("role").setPlaceholder("Select roles").setMaxValues(25);
Skyler Greyda16adf2023-03-05 10:22:12 +000071 mapped = await Promise.all(
72 ids.map(async (id) => {
73 return await interaction.guild!.roles.fetch(id).then((role) => role?.name ?? "Unknown Role");
74 })
75 );
76 render = ids.map((id) => client.logger.renderRole(id, interaction.guild!));
TheCodedProf486bca32023-02-02 16:49:44 -050077 break;
PineaFanb0d0c242023-02-05 10:59:45 +000078 }
79 case "channel": {
Skyler Greyda16adf2023-03-05 10:22:12 +000080 menu = new ChannelSelectMenuBuilder()
81 .setCustomId("channel")
82 .setPlaceholder("Select channels")
83 .setMaxValues(25);
84 mapped = await Promise.all(
85 ids.map(async (id) => {
86 return await interaction
87 .guild!.channels.fetch(id)
88 .then((channel) => channel?.name ?? "Unknown Role");
89 })
90 );
91 render = ids.map((id) => client.logger.renderChannel(id));
TheCodedProf486bca32023-02-02 16:49:44 -050092 break;
PineaFanb0d0c242023-02-05 10:59:45 +000093 }
TheCodedProf486bca32023-02-02 16:49:44 -050094 }
Skyler Greyda16adf2023-03-05 10:22:12 +000095 const removeOptions = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
96 new StringSelectMenuBuilder()
97 .setCustomId("remove")
98 .setPlaceholder("Remove")
99 .addOptions(
100 mapped.map((name, i) => new StringSelectMenuOptionBuilder().setLabel(name).setValue(ids[i]!))
101 )
102 .setDisabled(ids.length === 0)
103 );
TheCodedProf486bca32023-02-02 16:49:44 -0500104
105 const embed = new EmojiEmbed()
106 .setTitle(title)
107 .setEmoji(getEmojiByName("GUILD.SETTINGS.GREEN"))
108 .setDescription(`Select ${type}s:\n\nCurrent:\n` + (render.length > 0 ? render.join("\n") : "None"))
109 .setStatus("Success");
PineaFanb0d0c242023-02-05 10:59:45 +0000110 const components: ActionRowBuilder<
Skyler Greyda16adf2023-03-05 10:22:12 +0000111 | StringSelectMenuBuilder
112 | ButtonBuilder
113 | ChannelSelectMenuBuilder
114 | UserSelectMenuBuilder
115 | RoleSelectMenuBuilder
116 >[] = [new ActionRowBuilder<typeof menu>().addComponents(menu)];
117 if (ids.length > 0) components.push(removeOptions);
TheCodedProf486bca32023-02-02 16:49:44 -0500118 components.push(back);
119
Skyler Greyda16adf2023-03-05 10:22:12 +0000120 await interaction.editReply({ embeds: [embed], components: components });
TheCodedProf486bca32023-02-02 16:49:44 -0500121
122 let i: AnySelectMenuInteraction | ButtonInteraction;
123 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000124 i = await m.awaitMessageComponent({ filter: (i) => i.user.id === interaction.user.id, time: 300000 });
125 } catch (e) {
TheCodedProf486bca32023-02-02 16:49:44 -0500126 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +0000127 continue;
TheCodedProf486bca32023-02-02 16:49:44 -0500128 }
129
Skyler Greyda16adf2023-03-05 10:22:12 +0000130 if (i.isButton()) {
TheCodedProf486bca32023-02-02 16:49:44 -0500131 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000132 if (i.customId === "back") {
TheCodedProf486bca32023-02-02 16:49:44 -0500133 closed = true;
134 break;
135 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000136 } else if (i.isStringSelectMenu()) {
TheCodedProf486bca32023-02-02 16:49:44 -0500137 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000138 if (i.customId === "remove") {
139 ids = ids.filter((id) => id !== (i as StringSelectMenuInteraction).values[0]);
140 if (ids.length === 0) {
TheCodedProf486bca32023-02-02 16:49:44 -0500141 menu.data.disabled = true;
142 }
143 }
144 } else {
145 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000146 if (i.customId === "user") {
TheCodedProf486bca32023-02-02 16:49:44 -0500147 ids = ids.concat((i as UserSelectMenuInteraction).values);
Skyler Greyda16adf2023-03-05 10:22:12 +0000148 } else if (i.customId === "role") {
TheCodedProf486bca32023-02-02 16:49:44 -0500149 ids = ids.concat((i as RoleSelectMenuInteraction).values);
Skyler Greyda16adf2023-03-05 10:22:12 +0000150 } else if (i.customId === "channel") {
TheCodedProf486bca32023-02-02 16:49:44 -0500151 ids = ids.concat((i as ChannelSelectMenuInteraction).values);
152 }
153 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000154 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500155 return ids;
Skyler Greyda16adf2023-03-05 10:22:12 +0000156};
TheCodedProf8b3da212023-02-02 15:09:55 -0500157
Skyler Greyda16adf2023-03-05 10:22:12 +0000158const imageMenu = async (
159 interaction: StringSelectMenuInteraction,
160 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500161 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000162 current: {
163 NSFW: boolean;
164 size: boolean;
165 }
166): Promise<{ NSFW: boolean; size: boolean }> => {
TheCodedProf8b3da212023-02-02 15:09:55 -0500167 let closed = false;
168 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000169 const options = new ActionRowBuilder<ButtonBuilder>().addComponents(
170 new ButtonBuilder()
171 .setCustomId("back")
172 .setLabel("Back")
173 .setStyle(ButtonStyle.Secondary)
174 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
175 new ButtonBuilder()
176 .setCustomId("nsfw")
177 .setLabel("NSFW")
178 .setStyle(current.NSFW ? ButtonStyle.Success : ButtonStyle.Danger)
179 .setEmoji(emojiFromBoolean(current.NSFW, "id") as APIMessageComponentEmoji),
180 new ButtonBuilder()
181 .setCustomId("size")
182 .setLabel("Size")
183 .setStyle(current.size ? ButtonStyle.Success : ButtonStyle.Danger)
184 .setEmoji(emojiFromBoolean(current.size, "id") as APIMessageComponentEmoji)
185 );
TheCodedProf8b3da212023-02-02 15:09:55 -0500186
187 const embed = new EmojiEmbed()
188 .setTitle("Image Settings")
189 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000190 `${emojiFromBoolean(current.NSFW)} **NSFW**\n` + `${emojiFromBoolean(current.size)} **Size**\n`
TheCodedProf35e73712023-03-10 17:35:35 -0500191 )
192 .setFooter({
193 text: unsavedChanges ? "No changes made" : "Changes not saved"
194 });
TheCodedProf8b3da212023-02-02 15:09:55 -0500195
Skyler Greyda16adf2023-03-05 10:22:12 +0000196 await interaction.editReply({ embeds: [embed], components: [options] });
TheCodedProf8b3da212023-02-02 15:09:55 -0500197
198 let i: ButtonInteraction;
199 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000200 i = (await m.awaitMessageComponent({
201 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
202 time: 300000
203 })) as ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -0500204 } catch (e) {
205 return current;
206 }
207 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000208 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000209 case "back": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500210 closed = true;
211 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000212 }
213 case "nsfw": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500214 current.NSFW = !current.NSFW;
TheCodedProf35e73712023-03-10 17:35:35 -0500215 unsavedChanges = true;
TheCodedProf8b3da212023-02-02 15:09:55 -0500216 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000217 }
218 case "size": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500219 current.size = !current.size;
TheCodedProf35e73712023-03-10 17:35:35 -0500220 unsavedChanges = true;
TheCodedProf8b3da212023-02-02 15:09:55 -0500221 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000222 }
TheCodedProf8b3da212023-02-02 15:09:55 -0500223 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000224 } while (!closed);
TheCodedProf8b3da212023-02-02 15:09:55 -0500225 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000226};
TheCodedProf8b3da212023-02-02 15:09:55 -0500227
Skyler Greyda16adf2023-03-05 10:22:12 +0000228const wordMenu = async (
229 interaction: StringSelectMenuInteraction,
230 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500231 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000232 current: {
233 enabled: boolean;
234 words: { strict: string[]; loose: string[] };
235 allowed: { users: string[]; roles: string[]; channels: string[] };
236 }
237): Promise<{
238 enabled: boolean;
239 words: { strict: string[]; loose: string[] };
240 allowed: { users: string[]; roles: string[]; channels: string[] };
TheCodedProf8b3da212023-02-02 15:09:55 -0500241}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500242 let closed = false;
243 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000244 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
245 new ButtonBuilder()
246 .setCustomId("back")
247 .setLabel("Back")
248 .setStyle(ButtonStyle.Secondary)
249 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
250 new ButtonBuilder()
251 .setCustomId("enabled")
252 .setLabel("Enabled")
253 .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
254 .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji)
255 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500256
Skyler Greyda16adf2023-03-05 10:22:12 +0000257 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
258 new StringSelectMenuBuilder()
259 .setCustomId("edit")
260 .setPlaceholder("Edit... ")
261 .addOptions(
262 new StringSelectMenuOptionBuilder()
263 .setLabel("Words")
264 .setDescription("Edit your list of words to filter")
265 .setValue("words"),
266 new StringSelectMenuOptionBuilder()
267 .setLabel("Allowed Users")
268 .setDescription("Users who will be unaffected by the word filter")
269 .setValue("allowedUsers"),
270 new StringSelectMenuOptionBuilder()
271 .setLabel("Allowed Roles")
272 .setDescription("Roles that will be unaffected by the word filter")
273 .setValue("allowedRoles"),
274 new StringSelectMenuOptionBuilder()
275 .setLabel("Allowed Channels")
276 .setDescription("Channels where the word filter will not apply")
277 .setValue("allowedChannels")
278 )
279 .setDisabled(!current.enabled)
280 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500281
282 const embed = new EmojiEmbed()
283 .setTitle("Word Filters")
284 .setDescription(
285 `${emojiFromBoolean(current.enabled)} **Enabled**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000286 `**Strict Words:** ${listToAndMore(current.words.strict, 5)}\n` +
287 `**Loose Words:** ${listToAndMore(current.words.loose, 5)}\n\n` +
288 `**Users:** ` +
289 listToAndMore(
290 current.allowed.users.map((user) => `<@${user}>`),
291 5
292 ) +
293 `\n` +
294 `**Roles:** ` +
295 listToAndMore(
296 current.allowed.roles.map((role) => `<@&${role}>`),
297 5
298 ) +
299 `\n` +
300 `**Channels:** ` +
301 listToAndMore(
302 current.allowed.channels.map((channel) => `<#${channel}>`),
303 5
304 )
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500305 )
306 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500307 .setEmoji("GUILD.SETTINGS.GREEN")
308 .setFooter({
309 text: unsavedChanges ? "No changes made" : "Changes not saved"
310 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500311
Skyler Greyda16adf2023-03-05 10:22:12 +0000312 await interaction.editReply({ embeds: [embed], components: [selectMenu, buttons] });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500313
314 let i: ButtonInteraction | StringSelectMenuInteraction;
315 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000316 i = (await m.awaitMessageComponent({
317 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
318 time: 300000
319 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500320 } catch (e) {
321 closed = true;
322 break;
323 }
324
Skyler Greyda16adf2023-03-05 10:22:12 +0000325 if (i.isButton()) {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500326 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000327 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000328 case "back": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500329 closed = true;
330 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000331 }
332 case "enabled": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500333 current.enabled = !current.enabled;
TheCodedProf35e73712023-03-10 17:35:35 -0500334 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500335 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000336 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500337 }
338 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +0000339 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000340 case "words": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000341 await interaction.editReply({
342 embeds: [
343 new EmojiEmbed()
344 .setTitle("Word Filter")
345 .setDescription("Modal opened. If you can't see it, click back and try again.")
346 .setStatus("Success")
347 .setEmoji("GUILD.SETTINGS.GREEN")
348 ],
349 components: [
350 new ActionRowBuilder<ButtonBuilder>().addComponents(
351 new ButtonBuilder()
352 .setLabel("Back")
353 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
354 .setStyle(ButtonStyle.Primary)
355 .setCustomId("back")
356 )
357 ]
358 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500359 const modal = new ModalBuilder()
360 .setTitle("Word Filter")
361 .setCustomId("wordFilter")
362 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000363 new ActionRowBuilder<TextInputBuilder>().addComponents(
364 new TextInputBuilder()
365 .setCustomId("wordStrict")
366 .setLabel("Strict Words")
367 .setPlaceholder(
368 "Matches anywhere in the message, including surrounded by other characters"
369 )
370 .setValue(current.words.strict.join(", "))
371 .setStyle(TextInputStyle.Paragraph)
372 .setRequired(false)
373 ),
374 new ActionRowBuilder<TextInputBuilder>().addComponents(
375 new TextInputBuilder()
376 .setCustomId("wordLoose")
377 .setLabel("Loose Words")
378 .setPlaceholder(
379 "Matches only if the word is by itself, surrounded by spaces or punctuation"
380 )
381 .setValue(current.words.loose.join(", "))
382 .setStyle(TextInputStyle.Paragraph)
383 .setRequired(false)
384 )
385 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500386
387 await i.showModal(modal);
388 let out;
389 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500390 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500391 } catch (e) {
392 break;
393 }
394 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000395 if (out.isButton()) break;
396 current.words.strict = out.fields
397 .getTextInputValue("wordStrict")
398 .split(",")
399 .map((s) => s.trim())
400 .filter((s) => s.length > 0);
401 current.words.loose = out.fields
402 .getTextInputValue("wordLoose")
403 .split(",")
404 .map((s) => s.trim())
405 .filter((s) => s.length > 0);
TheCodedProf35e73712023-03-10 17:35:35 -0500406 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500407 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000408 }
409 case "allowedUsers": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500410 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000411 current.allowed.users = await toSelectMenu(
412 interaction,
413 m,
414 current.allowed.users,
415 "member",
416 "Word Filter"
417 );
TheCodedProf35e73712023-03-10 17:35:35 -0500418 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500419 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000420 }
421 case "allowedRoles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500422 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000423 current.allowed.roles = await toSelectMenu(
424 interaction,
425 m,
426 current.allowed.roles,
427 "role",
428 "Word Filter"
429 );
TheCodedProf35e73712023-03-10 17:35:35 -0500430 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500431 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000432 }
433 case "allowedChannels": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500434 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000435 current.allowed.channels = await toSelectMenu(
436 interaction,
437 m,
438 current.allowed.channels,
439 "channel",
440 "Word Filter"
441 );
TheCodedProf35e73712023-03-10 17:35:35 -0500442 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500443 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000444 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500445 }
446 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000447 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500448 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000449};
TheCodedProf8b3da212023-02-02 15:09:55 -0500450
Skyler Greyda16adf2023-03-05 10:22:12 +0000451const inviteMenu = async (
452 interaction: StringSelectMenuInteraction,
453 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500454 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000455 current: {
456 enabled: boolean;
457 allowed: { users: string[]; roles: string[]; channels: string[] };
458 }
459): Promise<{
460 enabled: boolean;
461 allowed: { users: string[]; roles: string[]; channels: string[] };
TheCodedProf8b3da212023-02-02 15:09:55 -0500462}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500463 let closed = false;
464 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000465 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
466 new ButtonBuilder()
467 .setCustomId("back")
468 .setLabel("Back")
469 .setStyle(ButtonStyle.Secondary)
470 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
471 new ButtonBuilder()
472 .setCustomId("enabled")
473 .setLabel(current.enabled ? "Enabled" : "Disabled")
474 .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
475 .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji)
476 );
477 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
478 new StringSelectMenuBuilder()
479 .setCustomId("toEdit")
480 .setPlaceholder("Edit your allow list")
481 .addOptions(
482 new StringSelectMenuOptionBuilder()
483 .setLabel("Users")
484 .setDescription("Users that are allowed to send invites")
485 .setValue("users"),
486 new StringSelectMenuOptionBuilder()
487 .setLabel("Roles")
488 .setDescription("Roles that are allowed to send invites")
489 .setValue("roles"),
490 new StringSelectMenuOptionBuilder()
491 .setLabel("Channels")
492 .setDescription("Channels that anyone is allowed to send invites in")
493 .setValue("channels")
TheCodedProf486bca32023-02-02 16:49:44 -0500494 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000495 .setDisabled(!current.enabled)
496 );
TheCodedProf486bca32023-02-02 16:49:44 -0500497
498 const embed = new EmojiEmbed()
499 .setTitle("Invite Settings")
500 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000501 "Automatically deletes invites sent by users (outside of staff members and self promotion channels)" +
502 `\n\n` +
503 `${emojiFromBoolean(current.enabled)} **${current.enabled ? "Enabled" : "Disabled"}**\n\n` +
504 `**Users:** ` +
505 listToAndMore(
506 current.allowed.users.map((user) => `<@${user}>`),
507 5
508 ) +
509 `\n` +
510 `**Roles:** ` +
511 listToAndMore(
512 current.allowed.roles.map((role) => `<@&${role}>`),
513 5
514 ) +
515 `\n` +
516 `**Channels:** ` +
517 listToAndMore(
518 current.allowed.channels.map((channel) => `<#${channel}>`),
519 5
520 )
TheCodedProf486bca32023-02-02 16:49:44 -0500521 )
522 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500523 .setEmoji("GUILD.SETTINGS.GREEN")
524 .setFooter({
525 text: unsavedChanges ? "No changes made" : "Changes not saved"
526 });
TheCodedProf486bca32023-02-02 16:49:44 -0500527
Skyler Greyda16adf2023-03-05 10:22:12 +0000528 await interaction.editReply({ embeds: [embed], components: [menu, buttons] });
TheCodedProf486bca32023-02-02 16:49:44 -0500529
530 let i: ButtonInteraction | StringSelectMenuInteraction;
531 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000532 i = (await m.awaitMessageComponent({
533 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
534 time: 300000
535 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf486bca32023-02-02 16:49:44 -0500536 } catch (e) {
537 return current;
538 }
539
Skyler Greyda16adf2023-03-05 10:22:12 +0000540 if (i.isButton()) {
TheCodedProf486bca32023-02-02 16:49:44 -0500541 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000542 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000543 case "back": {
TheCodedProf486bca32023-02-02 16:49:44 -0500544 closed = true;
545 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000546 }
547 case "enabled": {
TheCodedProf486bca32023-02-02 16:49:44 -0500548 current.enabled = !current.enabled;
TheCodedProf35e73712023-03-10 17:35:35 -0500549 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500550 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000551 }
TheCodedProf486bca32023-02-02 16:49:44 -0500552 }
553 } else {
554 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000555 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000556 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000557 current.allowed.users = await toSelectMenu(
558 interaction,
559 m,
560 current.allowed.users,
561 "member",
562 "Invite Settings"
563 );
TheCodedProf35e73712023-03-10 17:35:35 -0500564 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500565 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000566 }
567 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000568 current.allowed.roles = await toSelectMenu(
569 interaction,
570 m,
571 current.allowed.roles,
572 "role",
573 "Invite Settings"
574 );
TheCodedProf35e73712023-03-10 17:35:35 -0500575 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500576 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000577 }
578 case "channels": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000579 current.allowed.channels = await toSelectMenu(
580 interaction,
581 m,
582 current.allowed.channels,
583 "channel",
584 "Invite Settings"
585 );
TheCodedProf35e73712023-03-10 17:35:35 -0500586 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500587 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000588 }
TheCodedProf486bca32023-02-02 16:49:44 -0500589 }
590 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000591 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500592 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000593};
TheCodedProf8b3da212023-02-02 15:09:55 -0500594
Skyler Greyda16adf2023-03-05 10:22:12 +0000595const mentionMenu = async (
596 interaction: StringSelectMenuInteraction,
597 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500598 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000599 current: {
600 mass: number;
601 everyone: boolean;
602 roles: boolean;
603 allowed: {
604 roles: string[];
605 rolesToMention: string[];
606 users: string[];
607 channels: string[];
608 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500609 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000610): Promise<{
611 mass: number;
612 everyone: boolean;
613 roles: boolean;
TheCodedProf8b3da212023-02-02 15:09:55 -0500614 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000615 roles: string[];
616 rolesToMention: string[];
617 users: string[];
618 channels: string[];
619 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500620}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500621 let closed = false;
622
623 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000624 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
625 new ButtonBuilder()
626 .setCustomId("back")
627 .setLabel("Back")
628 .setStyle(ButtonStyle.Secondary)
629 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
630 new ButtonBuilder()
631 .setCustomId("everyone")
632 .setLabel(current.everyone ? "Everyone" : "No one")
633 .setStyle(current.everyone ? ButtonStyle.Success : ButtonStyle.Danger)
634 .setEmoji(emojiFromBoolean(current.everyone, "id") as APIMessageComponentEmoji),
635 new ButtonBuilder()
636 .setCustomId("roles")
637 .setLabel(current.roles ? "Roles" : "No roles")
638 .setStyle(current.roles ? ButtonStyle.Success : ButtonStyle.Danger)
639 .setEmoji(emojiFromBoolean(current.roles, "id") as APIMessageComponentEmoji)
640 );
641 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
642 new StringSelectMenuBuilder()
643 .setCustomId("toEdit")
644 .setPlaceholder("Edit mention settings")
645 .addOptions(
646 new StringSelectMenuOptionBuilder()
647 .setLabel("Mass Mention Amount")
648 .setDescription("The amount of mentions before the bot will delete the message")
649 .setValue("mass"),
650 new StringSelectMenuOptionBuilder()
651 .setLabel("Roles")
652 .setDescription("Roles that are able to be mentioned")
653 .setValue("roles")
654 )
655 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500656
Skyler Greyda16adf2023-03-05 10:22:12 +0000657 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
658 new StringSelectMenuBuilder()
659 .setCustomId("allowed")
660 .setPlaceholder("Edit exceptions")
661 .addOptions(
662 new StringSelectMenuOptionBuilder()
663 .setLabel("Users")
664 .setDescription("Users that are unaffected by the mention filter")
665 .setValue("users"),
666 new StringSelectMenuOptionBuilder()
667 .setLabel("Roles")
668 .setDescription("Roles that are unaffected by the mention filter")
669 .setValue("roles"),
670 new StringSelectMenuOptionBuilder()
671 .setLabel("Channels")
672 .setDescription("Channels where anyone is unaffected by the mention filter")
673 .setValue("channels")
674 )
675 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500676
677 const embed = new EmojiEmbed()
678 .setTitle("Mention Settings")
679 .setDescription(
680 `Log when members mention:\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000681 `${emojiFromBoolean(true)} **${current.mass}+ members** in one message\n` +
682 `${emojiFromBoolean(current.everyone)} **Everyone**\n` +
683 `${emojiFromBoolean(current.roles)} **Roles**\n` +
684 (current.allowed.rolesToMention.length > 0
685 ? `> *Except for ${listToAndMore(
686 current.allowed.rolesToMention.map((r) => `<@&${r}>`),
687 3
688 )}*\n`
689 : "") +
690 "\n" +
691 `Except if...\n` +
692 `> ${
693 current.allowed.users.length > 0
694 ? `Member is: ${listToAndMore(
695 current.allowed.users.map((u) => `<@${u}>`),
696 3
697 )}\n`
698 : ""
699 }` +
700 `> ${
701 current.allowed.roles.length > 0
702 ? `Member has role: ${listToAndMore(
703 current.allowed.roles.map((r) => `<@&${r}>`),
704 3
705 )}\n`
706 : ""
707 }` +
708 `> ${
709 current.allowed.channels.length > 0
710 ? `In channel: ${listToAndMore(
711 current.allowed.channels.map((c) => `<#${c}>`),
712 3
713 )}\n`
714 : ""
715 }`
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500716 )
717 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500718 .setEmoji("GUILD.SETTINGS.GREEN")
719 .setFooter({
720 text: unsavedChanges ? "No changes made" : "Changes not saved"
721 });;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500722
Skyler Greyda16adf2023-03-05 10:22:12 +0000723 await interaction.editReply({ embeds: [embed], components: [menu, allowedMenu, buttons] });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500724
725 let i: ButtonInteraction | StringSelectMenuInteraction;
726 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000727 i = (await m.awaitMessageComponent({
728 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
729 time: 300000
730 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500731 } catch (e) {
732 closed = true;
733 break;
734 }
735
Skyler Greyda16adf2023-03-05 10:22:12 +0000736 if (i.isButton()) {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500737 await i.deferUpdate();
738 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000739 case "back": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500740 closed = true;
741 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000742 }
743 case "everyone": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500744 current.everyone = !current.everyone;
TheCodedProf35e73712023-03-10 17:35:35 -0500745 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500746 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000747 }
748 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500749 current.roles = !current.roles;
TheCodedProf35e73712023-03-10 17:35:35 -0500750 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500751 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000752 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500753 }
754 } else {
755 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000756 case "toEdit": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500757 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000758 case "mass": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000759 await interaction.editReply({
760 embeds: [
761 new EmojiEmbed()
762 .setTitle("Word Filter")
763 .setDescription("Modal opened. If you can't see it, click back and try again.")
764 .setStatus("Success")
765 .setEmoji("GUILD.SETTINGS.GREEN")
766 ],
767 components: [
768 new ActionRowBuilder<ButtonBuilder>().addComponents(
769 new ButtonBuilder()
770 .setLabel("Back")
771 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
772 .setStyle(ButtonStyle.Primary)
773 .setCustomId("back")
774 )
775 ]
776 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500777 const modal = new ModalBuilder()
778 .setTitle("Mass Mention Amount")
779 .setCustomId("mass")
780 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000781 new ActionRowBuilder<TextInputBuilder>().addComponents(
782 new TextInputBuilder()
783 .setCustomId("mass")
784 .setPlaceholder("Amount")
785 .setMinLength(1)
786 .setMaxLength(3)
787 .setStyle(TextInputStyle.Short)
788 )
789 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500790 await i.showModal(modal);
791 let out;
792 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500793 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500794 } catch (e) {
795 break;
796 }
797 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000798 if (out.isButton()) break;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500799 current.mass = parseInt(out.fields.getTextInputValue("mass"));
TheCodedProf35e73712023-03-10 17:35:35 -0500800 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500801 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000802 }
803 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500804 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000805 current.allowed.rolesToMention = await toSelectMenu(
806 interaction,
807 m,
808 current.allowed.rolesToMention,
809 "role",
810 "Mention Settings"
811 );
TheCodedProf35e73712023-03-10 17:35:35 -0500812 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500813 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000814 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500815 }
816 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000817 }
818 case "allowed": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500819 await i.deferUpdate();
820 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000821 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000822 current.allowed.users = await toSelectMenu(
823 interaction,
824 m,
825 current.allowed.users,
826 "member",
827 "Mention Settings"
828 );
TheCodedProf35e73712023-03-10 17:35:35 -0500829 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500830 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000831 }
832 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000833 current.allowed.roles = await toSelectMenu(
834 interaction,
835 m,
836 current.allowed.roles,
837 "role",
838 "Mention Settings"
839 );
TheCodedProf35e73712023-03-10 17:35:35 -0500840 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500841 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000842 }
843 case "channels": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000844 current.allowed.channels = await toSelectMenu(
845 interaction,
846 m,
847 current.allowed.channels,
848 "channel",
849 "Mention Settings"
850 );
TheCodedProf35e73712023-03-10 17:35:35 -0500851 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500852 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000853 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500854 }
855 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000856 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500857 }
858 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000859 } while (!closed);
860 return current;
861};
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500862
Skyler Greyda16adf2023-03-05 10:22:12 +0000863const cleanMenu = async (
864 interaction: StringSelectMenuInteraction,
865 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500866 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000867 current?: {
868 channels?: string[];
869 allowed?: {
870 roles: string[];
871 users: string[];
872 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500873 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000874): Promise<{
875 channels: string[];
TheCodedProfad0b8202023-02-14 14:27:09 -0500876 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000877 roles: string[];
878 users: string[];
879 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500880}> => {
881 let closed = false;
Skyler Greyda16adf2023-03-05 10:22:12 +0000882 if (!current) current = { channels: [], allowed: { roles: [], users: [] } };
883 if (!current.channels) current.channels = [];
884 if (!current.allowed) current.allowed = { roles: [], users: [] };
TheCodedProfad0b8202023-02-14 14:27:09 -0500885
Skyler Greyda16adf2023-03-05 10:22:12 +0000886 const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(
887 new ChannelSelectMenuBuilder().setCustomId("toAdd").setPlaceholder("Select a channel")
888 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500889
Skyler Greyda16adf2023-03-05 10:22:12 +0000890 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
891 new StringSelectMenuBuilder()
892 .setCustomId("allowed")
893 .setPlaceholder("Edit exceptions")
894 .addOptions(
895 new StringSelectMenuOptionBuilder()
896 .setLabel("Users")
897 .setDescription("Users that are unaffected by the mention filter")
898 .setValue("users"),
899 new StringSelectMenuOptionBuilder()
900 .setLabel("Roles")
901 .setDescription("Roles that are unaffected by the mention filter")
902 .setValue("roles")
903 )
904 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500905
906 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000907 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
908 new ButtonBuilder()
909 .setCustomId("back")
910 .setLabel("Back")
911 .setStyle(ButtonStyle.Primary)
912 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
913 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500914
915 const embed = new EmojiEmbed()
916 .setTitle("Clean Settings")
917 .setEmoji("GUILD.SETTINGS.GREEN")
918 .setDescription(
919 `Current clean channels:\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000920 `${
921 current.channels.length > 0
922 ? listToAndMore(
923 current.channels.map((c) => `<#${c}>`),
924 10
925 )
926 : "None"
927 }\n\n`
TheCodedProfad0b8202023-02-14 14:27:09 -0500928 )
TheCodedProf35e73712023-03-10 17:35:35 -0500929 .setStatus("Success")
930 .setFooter({
931 text: unsavedChanges ? "No changes made" : "Changes not saved"
932 });
TheCodedProfad0b8202023-02-14 14:27:09 -0500933
Skyler Greyda16adf2023-03-05 10:22:12 +0000934 await interaction.editReply({ embeds: [embed], components: [channelMenu, allowedMenu, buttons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500935
936 let i: ButtonInteraction | ChannelSelectMenuInteraction;
937 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000938 i = (await m.awaitMessageComponent({
939 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
940 time: 300000
941 })) as ButtonInteraction | ChannelSelectMenuInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500942 } catch (e) {
943 closed = true;
944 break;
945 }
946 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000947 if (i.isButton()) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500948 switch (i.customId) {
949 case "back": {
950 closed = true;
951 break;
952 }
953 }
954 } else {
955 switch (i.customId) {
956 case "toAdd": {
TheCodedProf1807fb32023-02-20 14:33:48 -0500957 const channelEmbed = new EmojiEmbed()
TheCodedProfad0b8202023-02-14 14:27:09 -0500958 .setTitle("Clean Settings")
959 .setDescription(`Editing <#${i.values[0]}>`)
960 .setEmoji("GUILD.SETTINGS.GREEN")
Skyler Greyda16adf2023-03-05 10:22:12 +0000961 .setStatus("Success");
962 const channelButtons = new ActionRowBuilder<ButtonBuilder>().addComponents(
963 new ButtonBuilder()
964 .setCustomId("back")
965 .setLabel("Back")
966 .setStyle(ButtonStyle.Primary)
967 .setEmoji(getEmojiByName("CONTROL.LEFT", "id")),
968 new ButtonBuilder()
969 .setCustomId("switch")
970 .setLabel(current.channels.includes(i.values[0]!) ? "Remove" : "Add")
971 .setStyle(
972 current.channels.includes(i.values[0]!) ? ButtonStyle.Danger : ButtonStyle.Success
973 )
974 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500975
Skyler Greyda16adf2023-03-05 10:22:12 +0000976 await i.editReply({ embeds: [channelEmbed], components: [channelButtons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500977 let j: ButtonInteraction;
978 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000979 j = (await m.awaitMessageComponent({
980 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
981 time: 300000
982 })) as ButtonInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500983 } catch (e) {
984 closed = true;
985 break;
986 }
987 await j.deferUpdate();
988 switch (j.customId) {
989 case "back": {
990 break;
991 }
992 case "switch": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000993 if (current.channels.includes(i.values[0]!)) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500994 current.channels.splice(current.channels.indexOf(i.values[0]!), 1);
995 } else {
996 current.channels.push(i.values[0]!);
997 }
998 }
999 }
TheCodedProf35e73712023-03-10 17:35:35 -05001000 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001001 break;
1002 }
1003 case "allowed": {
1004 switch (i.values[0]) {
1005 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +00001006 current.allowed.users = await toSelectMenu(
1007 interaction,
1008 m,
1009 current.allowed.users,
1010 "member",
1011 "Mention Settings"
1012 );
TheCodedProf35e73712023-03-10 17:35:35 -05001013 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001014 break;
1015 }
1016 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +00001017 current.allowed.roles = await toSelectMenu(
1018 interaction,
1019 m,
1020 current.allowed.roles,
1021 "role",
1022 "Mention Settings"
1023 );
TheCodedProf35e73712023-03-10 17:35:35 -05001024 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001025 break;
1026 }
1027 }
1028 break;
1029 }
1030 }
1031 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001032 } while (!closed);
TheCodedProfad0b8202023-02-14 14:27:09 -05001033
TheCodedProf1807fb32023-02-20 14:33:48 -05001034 return current as {
Skyler Greyda16adf2023-03-05 10:22:12 +00001035 channels: string[];
TheCodedProf1807fb32023-02-20 14:33:48 -05001036 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +00001037 roles: string[];
1038 users: string[];
1039 };
TheCodedProf1807fb32023-02-20 14:33:48 -05001040 };
Skyler Greyda16adf2023-03-05 10:22:12 +00001041};
TheCodedProfad0b8202023-02-14 14:27:09 -05001042
TheCodedProf8b3da212023-02-02 15:09:55 -05001043const callback = async (interaction: CommandInteraction): Promise<void> => {
1044 if (!interaction.guild) return;
Skyler Greyda16adf2023-03-05 10:22:12 +00001045 const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
TheCodedProf35e73712023-03-10 17:35:35 -05001046 let config = (await client.database.guilds.read(interaction.guild.id)).filters;
TheCodedProf8b3da212023-02-02 15:09:55 -05001047
1048 let closed = false;
1049
TheCodedProf8b3da212023-02-02 15:09:55 -05001050
TheCodedProf35e73712023-03-10 17:35:35 -05001051 let current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001052 do {
TheCodedProf35e73712023-03-10 17:35:35 -05001053 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
1054 new ButtonBuilder().setCustomId("save").setLabel("Save").setStyle(ButtonStyle.Success).setDisabled(_.isEqual(config, current))
1055 );
Skyler Greyda16adf2023-03-05 10:22:12 +00001056 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
1057 new StringSelectMenuBuilder()
1058 .setCustomId("filter")
1059 .setPlaceholder("Select a filter to edit")
1060 .addOptions(
1061 new StringSelectMenuOptionBuilder()
1062 .setLabel("Invites")
1063 .setDescription("Automatically delete messages containing server invites")
1064 .setValue("invites"),
1065 new StringSelectMenuOptionBuilder()
1066 .setLabel("Mentions")
1067 .setDescription("Deletes messages with excessive mentions")
1068 .setValue("mentions"),
1069 new StringSelectMenuOptionBuilder()
1070 .setLabel("Words")
1071 .setDescription("Delete messages containing filtered words")
1072 .setValue("words"),
1073 new StringSelectMenuOptionBuilder()
1074 .setLabel("Malware")
1075 .setDescription("Automatically delete files and links containing malware")
1076 .setValue("malware"),
1077 new StringSelectMenuOptionBuilder()
1078 .setLabel("Images")
1079 .setDescription("Checks performed on images (NSFW, size checking, etc.)")
1080 .setValue("images"),
1081 new StringSelectMenuOptionBuilder()
1082 .setLabel("Clean")
1083 .setDescription("Automatically delete new messages in specific channels")
1084 .setValue("clean")
1085 )
1086 );
TheCodedProf8b3da212023-02-02 15:09:55 -05001087
1088 const embed = new EmojiEmbed()
1089 .setTitle("Automod Settings")
1090 .setDescription(
TheCodedProf486bca32023-02-02 16:49:44 -05001091 `${emojiFromBoolean(config.invite.enabled)} **Invites**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +00001092 `${emojiFromBoolean(
1093 config.pings.everyone || config.pings.mass > 0 || config.pings.roles
1094 )} **Mentions**\n` +
1095 `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` +
1096 `${emojiFromBoolean(config.malware)} **Malware**\n` +
1097 `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**\n` +
1098 `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n`
TheCodedProf8b3da212023-02-02 15:09:55 -05001099 )
TheCodedProf486bca32023-02-02 16:49:44 -05001100 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -05001101 .setEmoji("GUILD.SETTINGS.GREEN")
1102 .setFooter({
1103 text: _.isEqual(config, current) ? "No changes made" : "Changes not saved"
1104 });
TheCodedProf8b3da212023-02-02 15:09:55 -05001105
Skyler Greyda16adf2023-03-05 10:22:12 +00001106 await interaction.editReply({ embeds: [embed], components: [selectMenu, button] });
TheCodedProf8b3da212023-02-02 15:09:55 -05001107
1108 let i: StringSelectMenuInteraction | ButtonInteraction;
1109 try {
Skyler Greyda16adf2023-03-05 10:22:12 +00001110 i = (await m.awaitMessageComponent({
1111 filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
1112 time: 300000
1113 })) as StringSelectMenuInteraction | ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -05001114 } catch (e) {
1115 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +00001116 continue;
TheCodedProf8b3da212023-02-02 15:09:55 -05001117 }
TheCodedProf35e73712023-03-10 17:35:35 -05001118 await i.deferUpdate();
1119 if(i.isButton()) {
1120 await client.database.guilds.write(interaction.guild.id, { filters: current });
Skyler Grey16ecb172023-03-05 07:30:32 +00001121 await client.memory.forceUpdate(interaction.guild.id);
TheCodedProf35e73712023-03-10 17:35:35 -05001122 config = current;
1123 current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001124 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +00001125 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +00001126 case "invites": {
TheCodedProf35e73712023-03-10 17:35:35 -05001127 config.invite = await inviteMenu(i, m, _.isEqual(config, current), config.invite);
TheCodedProf8b3da212023-02-02 15:09:55 -05001128 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001129 }
1130 case "mentions": {
TheCodedProf35e73712023-03-10 17:35:35 -05001131 config.pings = await mentionMenu(i, m, _.isEqual(config, current), config.pings);
TheCodedProf8b3da212023-02-02 15:09:55 -05001132 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001133 }
1134 case "words": {
TheCodedProf35e73712023-03-10 17:35:35 -05001135 config.wordFilter = await wordMenu(i, m, _.isEqual(config, current), config.wordFilter);
TheCodedProf8b3da212023-02-02 15:09:55 -05001136 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001137 }
1138 case "malware": {
TheCodedProf8b3da212023-02-02 15:09:55 -05001139 config.malware = !config.malware;
1140 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001141 }
1142 case "images": {
TheCodedProf35e73712023-03-10 17:35:35 -05001143 const next = await imageMenu(i, m, _.isEqual(config, current), config.images);
PineaFanb0d0c242023-02-05 10:59:45 +00001144 config.images = next;
TheCodedProf8b3da212023-02-02 15:09:55 -05001145 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001146 }
TheCodedProfad0b8202023-02-14 14:27:09 -05001147 case "clean": {
TheCodedProf35e73712023-03-10 17:35:35 -05001148 const next = await cleanMenu(i, m, _.isEqual(config, current), config.clean);
TheCodedProfad0b8202023-02-14 14:27:09 -05001149 config.clean = next;
1150 break;
1151 }
TheCodedProf8b3da212023-02-02 15:09:55 -05001152 }
1153 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001154 } while (!closed);
1155 await interaction.deleteReply();
TheCodedProf8b3da212023-02-02 15:09:55 -05001156};
1157
1158const check = (interaction: CommandInteraction, _partial: boolean = false) => {
1159 const member = interaction.member as Discord.GuildMember;
1160 if (!member.permissions.has("ManageMessages"))
1161 return "You must have the *Manage Messages* permission to use this command";
1162 return true;
1163};
1164
1165export { command };
1166export { callback };
1167export { check };