blob: de8e7404bbd100bcada599cc274c6a98b1658562 [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")
pineafan10ac5542023-03-19 10:06:19 +0000189 .setStatus("Success")
190 // .setEmoji("") // TODO
TheCodedProf8b3da212023-02-02 15:09:55 -0500191 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000192 `${emojiFromBoolean(current.NSFW)} **NSFW**\n` + `${emojiFromBoolean(current.size)} **Size**\n`
TheCodedProf35e73712023-03-10 17:35:35 -0500193 )
194 .setFooter({
195 text: unsavedChanges ? "No changes made" : "Changes not saved"
196 });
TheCodedProf8b3da212023-02-02 15:09:55 -0500197
Skyler Greyda16adf2023-03-05 10:22:12 +0000198 await interaction.editReply({ embeds: [embed], components: [options] });
TheCodedProf8b3da212023-02-02 15:09:55 -0500199
200 let i: ButtonInteraction;
201 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000202 i = (await m.awaitMessageComponent({
203 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
204 time: 300000
205 })) as ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -0500206 } catch (e) {
207 return current;
208 }
209 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000210 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000211 case "back": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500212 closed = true;
213 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000214 }
215 case "nsfw": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500216 current.NSFW = !current.NSFW;
TheCodedProf35e73712023-03-10 17:35:35 -0500217 unsavedChanges = true;
TheCodedProf8b3da212023-02-02 15:09:55 -0500218 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000219 }
220 case "size": {
TheCodedProf8b3da212023-02-02 15:09:55 -0500221 current.size = !current.size;
TheCodedProf35e73712023-03-10 17:35:35 -0500222 unsavedChanges = true;
TheCodedProf8b3da212023-02-02 15:09:55 -0500223 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000224 }
TheCodedProf8b3da212023-02-02 15:09:55 -0500225 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000226 } while (!closed);
TheCodedProf8b3da212023-02-02 15:09:55 -0500227 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000228};
TheCodedProf8b3da212023-02-02 15:09:55 -0500229
Skyler Greyda16adf2023-03-05 10:22:12 +0000230const wordMenu = async (
231 interaction: StringSelectMenuInteraction,
232 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500233 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000234 current: {
235 enabled: boolean;
236 words: { strict: string[]; loose: string[] };
237 allowed: { users: string[]; roles: string[]; channels: string[] };
238 }
239): Promise<{
240 enabled: boolean;
241 words: { strict: string[]; loose: string[] };
242 allowed: { users: string[]; roles: string[]; channels: string[] };
TheCodedProf8b3da212023-02-02 15:09:55 -0500243}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500244 let closed = false;
245 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000246 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
247 new ButtonBuilder()
248 .setCustomId("back")
249 .setLabel("Back")
250 .setStyle(ButtonStyle.Secondary)
251 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
252 new ButtonBuilder()
253 .setCustomId("enabled")
254 .setLabel("Enabled")
255 .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
256 .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji)
257 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500258
Skyler Greyda16adf2023-03-05 10:22:12 +0000259 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
260 new StringSelectMenuBuilder()
261 .setCustomId("edit")
262 .setPlaceholder("Edit... ")
263 .addOptions(
264 new StringSelectMenuOptionBuilder()
265 .setLabel("Words")
266 .setDescription("Edit your list of words to filter")
267 .setValue("words"),
268 new StringSelectMenuOptionBuilder()
269 .setLabel("Allowed Users")
270 .setDescription("Users who will be unaffected by the word filter")
271 .setValue("allowedUsers"),
272 new StringSelectMenuOptionBuilder()
273 .setLabel("Allowed Roles")
274 .setDescription("Roles that will be unaffected by the word filter")
275 .setValue("allowedRoles"),
276 new StringSelectMenuOptionBuilder()
277 .setLabel("Allowed Channels")
278 .setDescription("Channels where the word filter will not apply")
279 .setValue("allowedChannels")
280 )
281 .setDisabled(!current.enabled)
282 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500283
284 const embed = new EmojiEmbed()
285 .setTitle("Word Filters")
286 .setDescription(
287 `${emojiFromBoolean(current.enabled)} **Enabled**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000288 `**Strict Words:** ${listToAndMore(current.words.strict, 5)}\n` +
289 `**Loose Words:** ${listToAndMore(current.words.loose, 5)}\n\n` +
290 `**Users:** ` +
291 listToAndMore(
292 current.allowed.users.map((user) => `<@${user}>`),
293 5
294 ) +
295 `\n` +
296 `**Roles:** ` +
297 listToAndMore(
298 current.allowed.roles.map((role) => `<@&${role}>`),
299 5
300 ) +
301 `\n` +
302 `**Channels:** ` +
303 listToAndMore(
304 current.allowed.channels.map((channel) => `<#${channel}>`),
305 5
306 )
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500307 )
308 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500309 .setEmoji("GUILD.SETTINGS.GREEN")
310 .setFooter({
311 text: unsavedChanges ? "No changes made" : "Changes not saved"
312 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500313
Skyler Greyda16adf2023-03-05 10:22:12 +0000314 await interaction.editReply({ embeds: [embed], components: [selectMenu, buttons] });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500315
316 let i: ButtonInteraction | StringSelectMenuInteraction;
317 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000318 i = (await m.awaitMessageComponent({
319 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
320 time: 300000
321 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500322 } catch (e) {
323 closed = true;
324 break;
325 }
326
Skyler Greyda16adf2023-03-05 10:22:12 +0000327 if (i.isButton()) {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500328 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000329 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000330 case "back": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500331 closed = true;
332 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000333 }
334 case "enabled": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500335 current.enabled = !current.enabled;
TheCodedProf35e73712023-03-10 17:35:35 -0500336 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500337 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000338 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500339 }
340 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +0000341 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000342 case "words": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000343 await interaction.editReply({
344 embeds: [
345 new EmojiEmbed()
346 .setTitle("Word Filter")
347 .setDescription("Modal opened. If you can't see it, click back and try again.")
348 .setStatus("Success")
349 .setEmoji("GUILD.SETTINGS.GREEN")
350 ],
351 components: [
352 new ActionRowBuilder<ButtonBuilder>().addComponents(
353 new ButtonBuilder()
354 .setLabel("Back")
355 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
356 .setStyle(ButtonStyle.Primary)
357 .setCustomId("back")
358 )
359 ]
360 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500361 const modal = new ModalBuilder()
362 .setTitle("Word Filter")
363 .setCustomId("wordFilter")
364 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000365 new ActionRowBuilder<TextInputBuilder>().addComponents(
366 new TextInputBuilder()
367 .setCustomId("wordStrict")
368 .setLabel("Strict Words")
369 .setPlaceholder(
370 "Matches anywhere in the message, including surrounded by other characters"
371 )
372 .setValue(current.words.strict.join(", "))
373 .setStyle(TextInputStyle.Paragraph)
374 .setRequired(false)
375 ),
376 new ActionRowBuilder<TextInputBuilder>().addComponents(
377 new TextInputBuilder()
378 .setCustomId("wordLoose")
379 .setLabel("Loose Words")
380 .setPlaceholder(
381 "Matches only if the word is by itself, surrounded by spaces or punctuation"
382 )
383 .setValue(current.words.loose.join(", "))
384 .setStyle(TextInputStyle.Paragraph)
385 .setRequired(false)
386 )
387 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500388
389 await i.showModal(modal);
390 let out;
391 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500392 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500393 } catch (e) {
394 break;
395 }
396 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000397 if (out.isButton()) break;
398 current.words.strict = out.fields
399 .getTextInputValue("wordStrict")
400 .split(",")
401 .map((s) => s.trim())
402 .filter((s) => s.length > 0);
403 current.words.loose = out.fields
404 .getTextInputValue("wordLoose")
405 .split(",")
406 .map((s) => s.trim())
407 .filter((s) => s.length > 0);
TheCodedProf35e73712023-03-10 17:35:35 -0500408 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500409 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000410 }
411 case "allowedUsers": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500412 await i.deferUpdate();
TheCodedProf36d99b32023-04-07 14:54:01 -0400413 current.allowed.users = _.cloneDeep(
414 await toSelectMenu(interaction, m, current.allowed.users, "member", "Word Filter")
415 );
TheCodedProf35e73712023-03-10 17:35:35 -0500416 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500417 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000418 }
419 case "allowedRoles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500420 await i.deferUpdate();
TheCodedProf36d99b32023-04-07 14:54:01 -0400421 current.allowed.roles = _.cloneDeep(
422 await toSelectMenu(interaction, m, current.allowed.roles, "role", "Word Filter")
423 );
TheCodedProf35e73712023-03-10 17:35:35 -0500424 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500425 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000426 }
427 case "allowedChannels": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500428 await i.deferUpdate();
TheCodedProf36d99b32023-04-07 14:54:01 -0400429 current.allowed.channels = _.cloneDeep(
430 await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Word Filter")
431 );
TheCodedProf35e73712023-03-10 17:35:35 -0500432 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500433 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000434 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500435 }
436 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000437 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500438 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000439};
TheCodedProf8b3da212023-02-02 15:09:55 -0500440
Skyler Greyda16adf2023-03-05 10:22:12 +0000441const inviteMenu = async (
442 interaction: StringSelectMenuInteraction,
443 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500444 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000445 current: {
446 enabled: boolean;
447 allowed: { users: string[]; roles: string[]; channels: string[] };
448 }
449): Promise<{
450 enabled: boolean;
451 allowed: { users: string[]; roles: string[]; channels: string[] };
TheCodedProf8b3da212023-02-02 15:09:55 -0500452}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500453 let closed = false;
454 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000455 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
456 new ButtonBuilder()
457 .setCustomId("back")
458 .setLabel("Back")
459 .setStyle(ButtonStyle.Secondary)
460 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
461 new ButtonBuilder()
462 .setCustomId("enabled")
463 .setLabel(current.enabled ? "Enabled" : "Disabled")
464 .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
465 .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji)
466 );
467 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
468 new StringSelectMenuBuilder()
469 .setCustomId("toEdit")
470 .setPlaceholder("Edit your allow list")
471 .addOptions(
472 new StringSelectMenuOptionBuilder()
473 .setLabel("Users")
474 .setDescription("Users that are allowed to send invites")
475 .setValue("users"),
476 new StringSelectMenuOptionBuilder()
477 .setLabel("Roles")
478 .setDescription("Roles that are allowed to send invites")
479 .setValue("roles"),
480 new StringSelectMenuOptionBuilder()
481 .setLabel("Channels")
482 .setDescription("Channels that anyone is allowed to send invites in")
483 .setValue("channels")
TheCodedProf486bca32023-02-02 16:49:44 -0500484 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000485 .setDisabled(!current.enabled)
486 );
TheCodedProf486bca32023-02-02 16:49:44 -0500487
488 const embed = new EmojiEmbed()
489 .setTitle("Invite Settings")
490 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000491 "Automatically deletes invites sent by users (outside of staff members and self promotion channels)" +
492 `\n\n` +
493 `${emojiFromBoolean(current.enabled)} **${current.enabled ? "Enabled" : "Disabled"}**\n\n` +
494 `**Users:** ` +
495 listToAndMore(
496 current.allowed.users.map((user) => `<@${user}>`),
497 5
498 ) +
499 `\n` +
500 `**Roles:** ` +
501 listToAndMore(
502 current.allowed.roles.map((role) => `<@&${role}>`),
503 5
504 ) +
505 `\n` +
506 `**Channels:** ` +
507 listToAndMore(
508 current.allowed.channels.map((channel) => `<#${channel}>`),
509 5
510 )
TheCodedProf486bca32023-02-02 16:49:44 -0500511 )
512 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500513 .setEmoji("GUILD.SETTINGS.GREEN")
514 .setFooter({
515 text: unsavedChanges ? "No changes made" : "Changes not saved"
516 });
TheCodedProf486bca32023-02-02 16:49:44 -0500517
Skyler Greyda16adf2023-03-05 10:22:12 +0000518 await interaction.editReply({ embeds: [embed], components: [menu, buttons] });
TheCodedProf486bca32023-02-02 16:49:44 -0500519
520 let i: ButtonInteraction | StringSelectMenuInteraction;
521 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000522 i = (await m.awaitMessageComponent({
523 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
524 time: 300000
525 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf486bca32023-02-02 16:49:44 -0500526 } catch (e) {
527 return current;
528 }
529
Skyler Greyda16adf2023-03-05 10:22:12 +0000530 if (i.isButton()) {
TheCodedProf486bca32023-02-02 16:49:44 -0500531 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000532 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000533 case "back": {
TheCodedProf486bca32023-02-02 16:49:44 -0500534 closed = true;
535 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000536 }
537 case "enabled": {
TheCodedProf486bca32023-02-02 16:49:44 -0500538 current.enabled = !current.enabled;
TheCodedProf35e73712023-03-10 17:35:35 -0500539 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500540 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000541 }
TheCodedProf486bca32023-02-02 16:49:44 -0500542 }
543 } else {
544 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000545 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000546 case "users": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400547 current.allowed.users = _.cloneDeep(
548 await toSelectMenu(interaction, m, current.allowed.users, "member", "Invite Settings")
549 );
TheCodedProf35e73712023-03-10 17:35:35 -0500550 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500551 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000552 }
553 case "roles": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400554 current.allowed.roles = _.cloneDeep(
555 await toSelectMenu(interaction, m, current.allowed.roles, "role", "Invite Settings")
556 );
TheCodedProf35e73712023-03-10 17:35:35 -0500557 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500558 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000559 }
560 case "channels": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400561 current.allowed.channels = _.cloneDeep(
562 await toSelectMenu(interaction, m, current.allowed.channels, "channel", "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 }
TheCodedProf486bca32023-02-02 16:49:44 -0500567 }
568 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000569 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500570 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000571};
TheCodedProf8b3da212023-02-02 15:09:55 -0500572
Skyler Greyda16adf2023-03-05 10:22:12 +0000573const mentionMenu = async (
574 interaction: StringSelectMenuInteraction,
575 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500576 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000577 current: {
578 mass: number;
579 everyone: boolean;
580 roles: boolean;
581 allowed: {
582 roles: string[];
583 rolesToMention: string[];
584 users: string[];
585 channels: string[];
586 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500587 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000588): Promise<{
589 mass: number;
590 everyone: boolean;
591 roles: boolean;
TheCodedProf8b3da212023-02-02 15:09:55 -0500592 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000593 roles: string[];
594 rolesToMention: string[];
595 users: string[];
596 channels: string[];
597 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500598}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500599 let closed = false;
600
601 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000602 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
603 new ButtonBuilder()
604 .setCustomId("back")
605 .setLabel("Back")
606 .setStyle(ButtonStyle.Secondary)
607 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
608 new ButtonBuilder()
609 .setCustomId("everyone")
610 .setLabel(current.everyone ? "Everyone" : "No one")
611 .setStyle(current.everyone ? ButtonStyle.Success : ButtonStyle.Danger)
612 .setEmoji(emojiFromBoolean(current.everyone, "id") as APIMessageComponentEmoji),
613 new ButtonBuilder()
614 .setCustomId("roles")
615 .setLabel(current.roles ? "Roles" : "No roles")
616 .setStyle(current.roles ? ButtonStyle.Success : ButtonStyle.Danger)
617 .setEmoji(emojiFromBoolean(current.roles, "id") as APIMessageComponentEmoji)
618 );
619 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
620 new StringSelectMenuBuilder()
621 .setCustomId("toEdit")
622 .setPlaceholder("Edit mention settings")
623 .addOptions(
624 new StringSelectMenuOptionBuilder()
625 .setLabel("Mass Mention Amount")
626 .setDescription("The amount of mentions before the bot will delete the message")
627 .setValue("mass"),
628 new StringSelectMenuOptionBuilder()
629 .setLabel("Roles")
630 .setDescription("Roles that are able to be mentioned")
631 .setValue("roles")
632 )
633 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500634
Skyler Greyda16adf2023-03-05 10:22:12 +0000635 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
636 new StringSelectMenuBuilder()
637 .setCustomId("allowed")
pineafan9ca34cd2023-03-21 18:45:58 +0000638 .setPlaceholder("Edit allowed list")
Skyler Greyda16adf2023-03-05 10:22:12 +0000639 .addOptions(
640 new StringSelectMenuOptionBuilder()
641 .setLabel("Users")
642 .setDescription("Users that are unaffected by the mention filter")
643 .setValue("users"),
644 new StringSelectMenuOptionBuilder()
645 .setLabel("Roles")
646 .setDescription("Roles that are unaffected by the mention filter")
647 .setValue("roles"),
648 new StringSelectMenuOptionBuilder()
649 .setLabel("Channels")
650 .setDescription("Channels where anyone is unaffected by the mention filter")
651 .setValue("channels")
652 )
653 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500654
655 const embed = new EmojiEmbed()
656 .setTitle("Mention Settings")
657 .setDescription(
658 `Log when members mention:\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000659 `${emojiFromBoolean(true)} **${current.mass}+ members** in one message\n` +
660 `${emojiFromBoolean(current.everyone)} **Everyone**\n` +
661 `${emojiFromBoolean(current.roles)} **Roles**\n` +
662 (current.allowed.rolesToMention.length > 0
663 ? `> *Except for ${listToAndMore(
pineafan7c2aedd2023-03-27 16:54:52 +0100664 current.allowed.rolesToMention.map((r) => `<@&${r}>`),
665 3
666 )}*\n`
Skyler Greyda16adf2023-03-05 10:22:12 +0000667 : "") +
668 "\n" +
669 `Except if...\n` +
pineafan9ca34cd2023-03-21 18:45:58 +0000670 (current.allowed.users.length > 0
671 ? `> Member is: ${listToAndMore(
pineafan7c2aedd2023-03-27 16:54:52 +0100672 current.allowed.users.map((u) => `<@${u}>`),
673 3
674 )}\n`
pineafan9ca34cd2023-03-21 18:45:58 +0000675 : "") +
676 (current.allowed.roles.length > 0
677 ? `> Member has role: ${listToAndMore(
pineafan7c2aedd2023-03-27 16:54:52 +0100678 current.allowed.roles.map((r) => `<@&${r}>`),
679 3
680 )}\n`
pineafan9ca34cd2023-03-21 18:45:58 +0000681 : "") +
682 (current.allowed.channels.length > 0
683 ? `> In channel: ${listToAndMore(
pineafan7c2aedd2023-03-27 16:54:52 +0100684 current.allowed.channels.map((c) => `<#${c}>`),
685 3
686 )}\n`
pineafan9ca34cd2023-03-21 18:45:58 +0000687 : "") +
pineafan7c2aedd2023-03-27 16:54:52 +0100688 (current.allowed.users.length == 0 ||
689 current.allowed.roles.length == 0 ||
690 current.allowed.channels.length == 0
PineappleFan07868982023-03-30 17:36:47 +0100691 ? "> *Nobody on allowed lists*\n"
pineafan7c2aedd2023-03-27 16:54:52 +0100692 : "")
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500693 )
694 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500695 .setEmoji("GUILD.SETTINGS.GREEN")
696 .setFooter({
697 text: unsavedChanges ? "No changes made" : "Changes not saved"
TheCodedProfca29ebb2023-03-10 17:40:09 -0500698 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500699
Skyler Greyda16adf2023-03-05 10:22:12 +0000700 await interaction.editReply({ embeds: [embed], components: [menu, allowedMenu, buttons] });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500701
702 let i: ButtonInteraction | StringSelectMenuInteraction;
703 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000704 i = (await m.awaitMessageComponent({
705 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
706 time: 300000
707 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500708 } catch (e) {
709 closed = true;
710 break;
711 }
712
Skyler Greyda16adf2023-03-05 10:22:12 +0000713 if (i.isButton()) {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500714 await i.deferUpdate();
715 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000716 case "back": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500717 closed = true;
718 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000719 }
720 case "everyone": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500721 current.everyone = !current.everyone;
TheCodedProf35e73712023-03-10 17:35:35 -0500722 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500723 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000724 }
725 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500726 current.roles = !current.roles;
TheCodedProf35e73712023-03-10 17:35:35 -0500727 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500728 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000729 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500730 }
731 } else {
732 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000733 case "toEdit": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500734 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000735 case "mass": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000736 await interaction.editReply({
737 embeds: [
738 new EmojiEmbed()
739 .setTitle("Word Filter")
740 .setDescription("Modal opened. If you can't see it, click back and try again.")
741 .setStatus("Success")
742 .setEmoji("GUILD.SETTINGS.GREEN")
743 ],
744 components: [
745 new ActionRowBuilder<ButtonBuilder>().addComponents(
746 new ButtonBuilder()
747 .setLabel("Back")
748 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
749 .setStyle(ButtonStyle.Primary)
750 .setCustomId("back")
751 )
752 ]
753 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500754 const modal = new ModalBuilder()
755 .setTitle("Mass Mention Amount")
756 .setCustomId("mass")
757 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000758 new ActionRowBuilder<TextInputBuilder>().addComponents(
759 new TextInputBuilder()
TheCodedProfe49649c2023-04-23 14:31:00 -0400760 .setLabel("Amount")
Skyler Greyda16adf2023-03-05 10:22:12 +0000761 .setCustomId("mass")
TheCodedProfe49649c2023-04-23 14:31:00 -0400762 .setPlaceholder(current.mass === 5 ? "Amount" : current.mass.toString())
Skyler Greyda16adf2023-03-05 10:22:12 +0000763 .setMinLength(1)
764 .setMaxLength(3)
765 .setStyle(TextInputStyle.Short)
766 )
767 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500768 await i.showModal(modal);
769 let out;
770 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500771 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500772 } catch (e) {
773 break;
774 }
775 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000776 if (out.isButton()) break;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500777 current.mass = parseInt(out.fields.getTextInputValue("mass"));
TheCodedProf35e73712023-03-10 17:35:35 -0500778 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500779 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000780 }
781 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500782 await i.deferUpdate();
TheCodedProf36d99b32023-04-07 14:54:01 -0400783 current.allowed.rolesToMention = _.cloneDeep(
784 await toSelectMenu(
785 interaction,
786 m,
787 current.allowed.rolesToMention,
788 "role",
789 "Mention Settings"
790 )
791 );
TheCodedProf35e73712023-03-10 17:35:35 -0500792 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500793 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000794 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500795 }
796 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000797 }
798 case "allowed": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500799 await i.deferUpdate();
800 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000801 case "users": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400802 current.allowed.users = _.cloneDeep(
803 await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings")
804 );
TheCodedProf35e73712023-03-10 17:35:35 -0500805 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500806 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000807 }
808 case "roles": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400809 current.allowed.roles = _.cloneDeep(
810 await toSelectMenu(interaction, m, current.allowed.roles, "role", "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 }
815 case "channels": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400816 current.allowed.channels = _.cloneDeep(
817 await toSelectMenu(
818 interaction,
819 m,
820 current.allowed.channels,
821 "channel",
822 "Mention Settings"
823 )
824 );
TheCodedProf35e73712023-03-10 17:35:35 -0500825 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500826 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000827 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500828 }
829 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000830 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500831 }
832 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000833 } while (!closed);
834 return current;
835};
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500836
Skyler Greyda16adf2023-03-05 10:22:12 +0000837const cleanMenu = async (
838 interaction: StringSelectMenuInteraction,
839 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500840 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000841 current?: {
842 channels?: string[];
843 allowed?: {
844 roles: string[];
845 users: string[];
846 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500847 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000848): Promise<{
849 channels: string[];
TheCodedProfad0b8202023-02-14 14:27:09 -0500850 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000851 roles: string[];
852 users: string[];
853 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500854}> => {
855 let closed = false;
Skyler Greyda16adf2023-03-05 10:22:12 +0000856 if (!current) current = { channels: [], allowed: { roles: [], users: [] } };
857 if (!current.channels) current.channels = [];
858 if (!current.allowed) current.allowed = { roles: [], users: [] };
TheCodedProfad0b8202023-02-14 14:27:09 -0500859
Skyler Greyda16adf2023-03-05 10:22:12 +0000860 const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(
861 new ChannelSelectMenuBuilder().setCustomId("toAdd").setPlaceholder("Select a channel")
862 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500863
Skyler Greyda16adf2023-03-05 10:22:12 +0000864 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
865 new StringSelectMenuBuilder()
866 .setCustomId("allowed")
867 .setPlaceholder("Edit exceptions")
868 .addOptions(
869 new StringSelectMenuOptionBuilder()
870 .setLabel("Users")
871 .setDescription("Users that are unaffected by the mention filter")
872 .setValue("users"),
873 new StringSelectMenuOptionBuilder()
874 .setLabel("Roles")
875 .setDescription("Roles that are unaffected by the mention filter")
876 .setValue("roles")
877 )
878 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500879
880 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000881 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
882 new ButtonBuilder()
883 .setCustomId("back")
884 .setLabel("Back")
885 .setStyle(ButtonStyle.Primary)
886 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
887 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500888
889 const embed = new EmojiEmbed()
890 .setTitle("Clean Settings")
891 .setEmoji("GUILD.SETTINGS.GREEN")
892 .setDescription(
893 `Current clean channels:\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000894 `${
895 current.channels.length > 0
896 ? listToAndMore(
897 current.channels.map((c) => `<#${c}>`),
898 10
899 )
900 : "None"
901 }\n\n`
TheCodedProfad0b8202023-02-14 14:27:09 -0500902 )
TheCodedProf35e73712023-03-10 17:35:35 -0500903 .setStatus("Success")
904 .setFooter({
905 text: unsavedChanges ? "No changes made" : "Changes not saved"
906 });
TheCodedProfad0b8202023-02-14 14:27:09 -0500907
Skyler Greyda16adf2023-03-05 10:22:12 +0000908 await interaction.editReply({ embeds: [embed], components: [channelMenu, allowedMenu, buttons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500909
910 let i: ButtonInteraction | ChannelSelectMenuInteraction;
911 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000912 i = (await m.awaitMessageComponent({
913 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
914 time: 300000
915 })) as ButtonInteraction | ChannelSelectMenuInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500916 } catch (e) {
917 closed = true;
918 break;
919 }
920 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000921 if (i.isButton()) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500922 switch (i.customId) {
923 case "back": {
924 closed = true;
925 break;
926 }
927 }
928 } else {
929 switch (i.customId) {
930 case "toAdd": {
TheCodedProf1807fb32023-02-20 14:33:48 -0500931 const channelEmbed = new EmojiEmbed()
TheCodedProfad0b8202023-02-14 14:27:09 -0500932 .setTitle("Clean Settings")
933 .setDescription(`Editing <#${i.values[0]}>`)
934 .setEmoji("GUILD.SETTINGS.GREEN")
Skyler Greyda16adf2023-03-05 10:22:12 +0000935 .setStatus("Success");
936 const channelButtons = new ActionRowBuilder<ButtonBuilder>().addComponents(
937 new ButtonBuilder()
938 .setCustomId("back")
939 .setLabel("Back")
940 .setStyle(ButtonStyle.Primary)
941 .setEmoji(getEmojiByName("CONTROL.LEFT", "id")),
942 new ButtonBuilder()
943 .setCustomId("switch")
944 .setLabel(current.channels.includes(i.values[0]!) ? "Remove" : "Add")
945 .setStyle(
946 current.channels.includes(i.values[0]!) ? ButtonStyle.Danger : ButtonStyle.Success
947 )
948 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500949
Skyler Greyda16adf2023-03-05 10:22:12 +0000950 await i.editReply({ embeds: [channelEmbed], components: [channelButtons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500951 let j: ButtonInteraction;
952 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000953 j = (await m.awaitMessageComponent({
954 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
955 time: 300000
956 })) as ButtonInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500957 } catch (e) {
958 closed = true;
959 break;
960 }
961 await j.deferUpdate();
962 switch (j.customId) {
963 case "back": {
964 break;
965 }
966 case "switch": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000967 if (current.channels.includes(i.values[0]!)) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500968 current.channels.splice(current.channels.indexOf(i.values[0]!), 1);
969 } else {
970 current.channels.push(i.values[0]!);
971 }
972 }
973 }
TheCodedProf35e73712023-03-10 17:35:35 -0500974 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500975 break;
976 }
977 case "allowed": {
978 switch (i.values[0]) {
979 case "users": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400980 current.allowed.users = _.cloneDeep(
981 await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings")
982 );
TheCodedProf35e73712023-03-10 17:35:35 -0500983 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500984 break;
985 }
986 case "roles": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400987 current.allowed.roles = _.cloneDeep(
988 await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings")
989 );
TheCodedProf35e73712023-03-10 17:35:35 -0500990 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500991 break;
992 }
993 }
994 break;
995 }
996 }
997 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000998 } while (!closed);
TheCodedProfad0b8202023-02-14 14:27:09 -0500999
TheCodedProf1807fb32023-02-20 14:33:48 -05001000 return current as {
Skyler Greyda16adf2023-03-05 10:22:12 +00001001 channels: string[];
TheCodedProf1807fb32023-02-20 14:33:48 -05001002 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +00001003 roles: string[];
1004 users: string[];
1005 };
TheCodedProf1807fb32023-02-20 14:33:48 -05001006 };
Skyler Greyda16adf2023-03-05 10:22:12 +00001007};
TheCodedProfad0b8202023-02-14 14:27:09 -05001008
TheCodedProf8b3da212023-02-02 15:09:55 -05001009const callback = async (interaction: CommandInteraction): Promise<void> => {
1010 if (!interaction.guild) return;
Skyler Greyda16adf2023-03-05 10:22:12 +00001011 const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
TheCodedProf35e73712023-03-10 17:35:35 -05001012 let config = (await client.database.guilds.read(interaction.guild.id)).filters;
TheCodedProf8b3da212023-02-02 15:09:55 -05001013
1014 let closed = false;
1015
TheCodedProf35e73712023-03-10 17:35:35 -05001016 let current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001017 do {
TheCodedProf35e73712023-03-10 17:35:35 -05001018 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProfca29ebb2023-03-10 17:40:09 -05001019 new ButtonBuilder()
1020 .setCustomId("save")
1021 .setLabel("Save")
1022 .setStyle(ButtonStyle.Success)
1023 .setDisabled(_.isEqual(config, current))
TheCodedProf35e73712023-03-10 17:35:35 -05001024 );
Skyler Greyda16adf2023-03-05 10:22:12 +00001025 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
1026 new StringSelectMenuBuilder()
1027 .setCustomId("filter")
1028 .setPlaceholder("Select a filter to edit")
1029 .addOptions(
1030 new StringSelectMenuOptionBuilder()
1031 .setLabel("Invites")
1032 .setDescription("Automatically delete messages containing server invites")
1033 .setValue("invites"),
1034 new StringSelectMenuOptionBuilder()
1035 .setLabel("Mentions")
1036 .setDescription("Deletes messages with excessive mentions")
1037 .setValue("mentions"),
1038 new StringSelectMenuOptionBuilder()
1039 .setLabel("Words")
1040 .setDescription("Delete messages containing filtered words")
1041 .setValue("words"),
1042 new StringSelectMenuOptionBuilder()
1043 .setLabel("Malware")
1044 .setDescription("Automatically delete files and links containing malware")
1045 .setValue("malware"),
1046 new StringSelectMenuOptionBuilder()
1047 .setLabel("Images")
1048 .setDescription("Checks performed on images (NSFW, size checking, etc.)")
1049 .setValue("images"),
1050 new StringSelectMenuOptionBuilder()
1051 .setLabel("Clean")
1052 .setDescription("Automatically delete new messages in specific channels")
1053 .setValue("clean")
1054 )
1055 );
TheCodedProf8b3da212023-02-02 15:09:55 -05001056
1057 const embed = new EmojiEmbed()
1058 .setTitle("Automod Settings")
1059 .setDescription(
TheCodedProf486bca32023-02-02 16:49:44 -05001060 `${emojiFromBoolean(config.invite.enabled)} **Invites**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +00001061 `${emojiFromBoolean(
1062 config.pings.everyone || config.pings.mass > 0 || config.pings.roles
1063 )} **Mentions**\n` +
1064 `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` +
1065 `${emojiFromBoolean(config.malware)} **Malware**\n` +
1066 `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**\n` +
1067 `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n`
TheCodedProf8b3da212023-02-02 15:09:55 -05001068 )
TheCodedProf486bca32023-02-02 16:49:44 -05001069 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -05001070 .setEmoji("GUILD.SETTINGS.GREEN")
1071 .setFooter({
1072 text: _.isEqual(config, current) ? "No changes made" : "Changes not saved"
1073 });
TheCodedProf8b3da212023-02-02 15:09:55 -05001074
Skyler Greyda16adf2023-03-05 10:22:12 +00001075 await interaction.editReply({ embeds: [embed], components: [selectMenu, button] });
TheCodedProf8b3da212023-02-02 15:09:55 -05001076
1077 let i: StringSelectMenuInteraction | ButtonInteraction;
1078 try {
Skyler Greyda16adf2023-03-05 10:22:12 +00001079 i = (await m.awaitMessageComponent({
1080 filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
1081 time: 300000
1082 })) as StringSelectMenuInteraction | ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -05001083 } catch (e) {
1084 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +00001085 continue;
TheCodedProf8b3da212023-02-02 15:09:55 -05001086 }
TheCodedProf35e73712023-03-10 17:35:35 -05001087 await i.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -05001088 if (i.isButton()) {
TheCodedProf35e73712023-03-10 17:35:35 -05001089 await client.database.guilds.write(interaction.guild.id, { filters: current });
Skyler Grey16ecb172023-03-05 07:30:32 +00001090 await client.memory.forceUpdate(interaction.guild.id);
TheCodedProf21ec2aa2023-04-22 17:32:48 -04001091 config = current;
TheCodedProf35e73712023-03-10 17:35:35 -05001092 current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001093 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +00001094 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +00001095 case "invites": {
TheCodedProf7ee6c132023-04-21 22:57:46 -04001096 current.invite = await inviteMenu(i, m, _.isEqual(config, current), current.invite);
TheCodedProf8b3da212023-02-02 15:09:55 -05001097 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001098 }
1099 case "mentions": {
TheCodedProf7ee6c132023-04-21 22:57:46 -04001100 current.pings = await mentionMenu(i, m, _.isEqual(config, current), current.pings);
TheCodedProf8b3da212023-02-02 15:09:55 -05001101 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001102 }
1103 case "words": {
TheCodedProf7ee6c132023-04-21 22:57:46 -04001104 current.wordFilter = await wordMenu(i, m, _.isEqual(config, current), current.wordFilter);
TheCodedProf8b3da212023-02-02 15:09:55 -05001105 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001106 }
1107 case "malware": {
TheCodedProf7ee6c132023-04-21 22:57:46 -04001108 current.malware = !current.malware;
TheCodedProf8b3da212023-02-02 15:09:55 -05001109 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001110 }
1111 case "images": {
TheCodedProf7ee6c132023-04-21 22:57:46 -04001112 const next = await imageMenu(i, m, _.isEqual(config, current), current.images);
1113 current.images = next;
TheCodedProf8b3da212023-02-02 15:09:55 -05001114 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001115 }
TheCodedProfad0b8202023-02-14 14:27:09 -05001116 case "clean": {
TheCodedProf35e73712023-03-10 17:35:35 -05001117 const next = await cleanMenu(i, m, _.isEqual(config, current), config.clean);
TheCodedProf7ee6c132023-04-21 22:57:46 -04001118 current.clean = next;
TheCodedProfad0b8202023-02-14 14:27:09 -05001119 break;
1120 }
TheCodedProf8b3da212023-02-02 15:09:55 -05001121 }
1122 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001123 } while (!closed);
1124 await interaction.deleteReply();
TheCodedProf8b3da212023-02-02 15:09:55 -05001125};
1126
1127const check = (interaction: CommandInteraction, _partial: boolean = false) => {
1128 const member = interaction.member as Discord.GuildMember;
1129 if (!member.permissions.has("ManageMessages"))
1130 return "You must have the *Manage Messages* permission to use this command";
1131 return true;
1132};
1133
1134export { command };
1135export { callback };
1136export { check };