blob: 7756ae7c93fb3fb8db076956b10b823b15904ba8 [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();
Skyler Greyda16adf2023-03-05 10:22:12 +0000413 current.allowed.users = await toSelectMenu(
414 interaction,
415 m,
416 current.allowed.users,
417 "member",
418 "Word Filter"
419 );
TheCodedProf35e73712023-03-10 17:35:35 -0500420 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500421 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000422 }
423 case "allowedRoles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500424 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000425 current.allowed.roles = await toSelectMenu(
426 interaction,
427 m,
428 current.allowed.roles,
429 "role",
430 "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 }
435 case "allowedChannels": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500436 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000437 current.allowed.channels = await toSelectMenu(
438 interaction,
439 m,
440 current.allowed.channels,
441 "channel",
442 "Word Filter"
443 );
TheCodedProf35e73712023-03-10 17:35:35 -0500444 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500445 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000446 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500447 }
448 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000449 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500450 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000451};
TheCodedProf8b3da212023-02-02 15:09:55 -0500452
Skyler Greyda16adf2023-03-05 10:22:12 +0000453const inviteMenu = async (
454 interaction: StringSelectMenuInteraction,
455 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500456 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000457 current: {
458 enabled: boolean;
459 allowed: { users: string[]; roles: string[]; channels: string[] };
460 }
461): Promise<{
462 enabled: boolean;
463 allowed: { users: string[]; roles: string[]; channels: string[] };
TheCodedProf8b3da212023-02-02 15:09:55 -0500464}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500465 let closed = false;
466 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000467 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
468 new ButtonBuilder()
469 .setCustomId("back")
470 .setLabel("Back")
471 .setStyle(ButtonStyle.Secondary)
472 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
473 new ButtonBuilder()
474 .setCustomId("enabled")
475 .setLabel(current.enabled ? "Enabled" : "Disabled")
476 .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
477 .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji)
478 );
479 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
480 new StringSelectMenuBuilder()
481 .setCustomId("toEdit")
482 .setPlaceholder("Edit your allow list")
483 .addOptions(
484 new StringSelectMenuOptionBuilder()
485 .setLabel("Users")
486 .setDescription("Users that are allowed to send invites")
487 .setValue("users"),
488 new StringSelectMenuOptionBuilder()
489 .setLabel("Roles")
490 .setDescription("Roles that are allowed to send invites")
491 .setValue("roles"),
492 new StringSelectMenuOptionBuilder()
493 .setLabel("Channels")
494 .setDescription("Channels that anyone is allowed to send invites in")
495 .setValue("channels")
TheCodedProf486bca32023-02-02 16:49:44 -0500496 )
Skyler Greyda16adf2023-03-05 10:22:12 +0000497 .setDisabled(!current.enabled)
498 );
TheCodedProf486bca32023-02-02 16:49:44 -0500499
500 const embed = new EmojiEmbed()
501 .setTitle("Invite Settings")
502 .setDescription(
Skyler Greyda16adf2023-03-05 10:22:12 +0000503 "Automatically deletes invites sent by users (outside of staff members and self promotion channels)" +
504 `\n\n` +
505 `${emojiFromBoolean(current.enabled)} **${current.enabled ? "Enabled" : "Disabled"}**\n\n` +
506 `**Users:** ` +
507 listToAndMore(
508 current.allowed.users.map((user) => `<@${user}>`),
509 5
510 ) +
511 `\n` +
512 `**Roles:** ` +
513 listToAndMore(
514 current.allowed.roles.map((role) => `<@&${role}>`),
515 5
516 ) +
517 `\n` +
518 `**Channels:** ` +
519 listToAndMore(
520 current.allowed.channels.map((channel) => `<#${channel}>`),
521 5
522 )
TheCodedProf486bca32023-02-02 16:49:44 -0500523 )
524 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500525 .setEmoji("GUILD.SETTINGS.GREEN")
526 .setFooter({
527 text: unsavedChanges ? "No changes made" : "Changes not saved"
528 });
TheCodedProf486bca32023-02-02 16:49:44 -0500529
Skyler Greyda16adf2023-03-05 10:22:12 +0000530 await interaction.editReply({ embeds: [embed], components: [menu, buttons] });
TheCodedProf486bca32023-02-02 16:49:44 -0500531
532 let i: ButtonInteraction | StringSelectMenuInteraction;
533 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000534 i = (await m.awaitMessageComponent({
535 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
536 time: 300000
537 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf486bca32023-02-02 16:49:44 -0500538 } catch (e) {
539 return current;
540 }
541
Skyler Greyda16adf2023-03-05 10:22:12 +0000542 if (i.isButton()) {
TheCodedProf486bca32023-02-02 16:49:44 -0500543 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000544 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000545 case "back": {
TheCodedProf486bca32023-02-02 16:49:44 -0500546 closed = true;
547 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000548 }
549 case "enabled": {
TheCodedProf486bca32023-02-02 16:49:44 -0500550 current.enabled = !current.enabled;
TheCodedProf35e73712023-03-10 17:35:35 -0500551 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500552 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000553 }
TheCodedProf486bca32023-02-02 16:49:44 -0500554 }
555 } else {
556 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000557 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000558 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000559 current.allowed.users = await toSelectMenu(
560 interaction,
561 m,
562 current.allowed.users,
563 "member",
564 "Invite Settings"
565 );
TheCodedProf35e73712023-03-10 17:35:35 -0500566 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500567 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000568 }
569 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000570 current.allowed.roles = await toSelectMenu(
571 interaction,
572 m,
573 current.allowed.roles,
574 "role",
575 "Invite Settings"
576 );
TheCodedProf35e73712023-03-10 17:35:35 -0500577 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500578 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000579 }
580 case "channels": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000581 current.allowed.channels = await toSelectMenu(
582 interaction,
583 m,
584 current.allowed.channels,
585 "channel",
586 "Invite Settings"
587 );
TheCodedProf35e73712023-03-10 17:35:35 -0500588 unsavedChanges = true;
TheCodedProf486bca32023-02-02 16:49:44 -0500589 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000590 }
TheCodedProf486bca32023-02-02 16:49:44 -0500591 }
592 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000593 } while (!closed);
TheCodedProf486bca32023-02-02 16:49:44 -0500594 return current;
Skyler Greyda16adf2023-03-05 10:22:12 +0000595};
TheCodedProf8b3da212023-02-02 15:09:55 -0500596
Skyler Greyda16adf2023-03-05 10:22:12 +0000597const mentionMenu = async (
598 interaction: StringSelectMenuInteraction,
599 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500600 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000601 current: {
602 mass: number;
603 everyone: boolean;
604 roles: boolean;
605 allowed: {
606 roles: string[];
607 rolesToMention: string[];
608 users: string[];
609 channels: string[];
610 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500611 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000612): Promise<{
613 mass: number;
614 everyone: boolean;
615 roles: boolean;
TheCodedProf8b3da212023-02-02 15:09:55 -0500616 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000617 roles: string[];
618 rolesToMention: string[];
619 users: string[];
620 channels: string[];
621 };
TheCodedProf8b3da212023-02-02 15:09:55 -0500622}> => {
TheCodedProf486bca32023-02-02 16:49:44 -0500623 let closed = false;
624
625 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000626 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
627 new ButtonBuilder()
628 .setCustomId("back")
629 .setLabel("Back")
630 .setStyle(ButtonStyle.Secondary)
631 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
632 new ButtonBuilder()
633 .setCustomId("everyone")
634 .setLabel(current.everyone ? "Everyone" : "No one")
635 .setStyle(current.everyone ? ButtonStyle.Success : ButtonStyle.Danger)
636 .setEmoji(emojiFromBoolean(current.everyone, "id") as APIMessageComponentEmoji),
637 new ButtonBuilder()
638 .setCustomId("roles")
639 .setLabel(current.roles ? "Roles" : "No roles")
640 .setStyle(current.roles ? ButtonStyle.Success : ButtonStyle.Danger)
641 .setEmoji(emojiFromBoolean(current.roles, "id") as APIMessageComponentEmoji)
642 );
643 const menu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
644 new StringSelectMenuBuilder()
645 .setCustomId("toEdit")
646 .setPlaceholder("Edit mention settings")
647 .addOptions(
648 new StringSelectMenuOptionBuilder()
649 .setLabel("Mass Mention Amount")
650 .setDescription("The amount of mentions before the bot will delete the message")
651 .setValue("mass"),
652 new StringSelectMenuOptionBuilder()
653 .setLabel("Roles")
654 .setDescription("Roles that are able to be mentioned")
655 .setValue("roles")
656 )
657 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500658
Skyler Greyda16adf2023-03-05 10:22:12 +0000659 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
660 new StringSelectMenuBuilder()
661 .setCustomId("allowed")
pineafan9ca34cd2023-03-21 18:45:58 +0000662 .setPlaceholder("Edit allowed list")
Skyler Greyda16adf2023-03-05 10:22:12 +0000663 .addOptions(
664 new StringSelectMenuOptionBuilder()
665 .setLabel("Users")
666 .setDescription("Users that are unaffected by the mention filter")
667 .setValue("users"),
668 new StringSelectMenuOptionBuilder()
669 .setLabel("Roles")
670 .setDescription("Roles that are unaffected by the mention filter")
671 .setValue("roles"),
672 new StringSelectMenuOptionBuilder()
673 .setLabel("Channels")
674 .setDescription("Channels where anyone is unaffected by the mention filter")
675 .setValue("channels")
676 )
677 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500678
679 const embed = new EmojiEmbed()
680 .setTitle("Mention Settings")
681 .setDescription(
682 `Log when members mention:\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000683 `${emojiFromBoolean(true)} **${current.mass}+ members** in one message\n` +
684 `${emojiFromBoolean(current.everyone)} **Everyone**\n` +
685 `${emojiFromBoolean(current.roles)} **Roles**\n` +
686 (current.allowed.rolesToMention.length > 0
687 ? `> *Except for ${listToAndMore(
pineafan9ca34cd2023-03-21 18:45:58 +0000688 current.allowed.rolesToMention.map((r) => `<@&${r}>`),
689 3
690 )}*\n`
Skyler Greyda16adf2023-03-05 10:22:12 +0000691 : "") +
692 "\n" +
693 `Except if...\n` +
pineafan9ca34cd2023-03-21 18:45:58 +0000694 (current.allowed.users.length > 0
695 ? `> Member is: ${listToAndMore(
696 current.allowed.users.map((u) => `<@${u}>`),
697 3
698 )}\n`
699 : "") +
700 (current.allowed.roles.length > 0
701 ? `> Member has role: ${listToAndMore(
702 current.allowed.roles.map((r) => `<@&${r}>`),
703 3
704 )}\n`
705 : "") +
706 (current.allowed.channels.length > 0
707 ? `> In channel: ${listToAndMore(
708 current.allowed.channels.map((c) => `<#${c}>`),
709 3
710 )}\n`
711 : "") +
712 (current.allowed.users.length == 0 || current.allowed.roles.length == 0 || current.allowed.channels.length == 0 ?
713 "> *No exceptions*\n" : ""
714 )
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500715 )
716 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -0500717 .setEmoji("GUILD.SETTINGS.GREEN")
718 .setFooter({
719 text: unsavedChanges ? "No changes made" : "Changes not saved"
TheCodedProfca29ebb2023-03-10 17:40:09 -0500720 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500721
Skyler Greyda16adf2023-03-05 10:22:12 +0000722 await interaction.editReply({ embeds: [embed], components: [menu, allowedMenu, buttons] });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500723
724 let i: ButtonInteraction | StringSelectMenuInteraction;
725 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000726 i = (await m.awaitMessageComponent({
727 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
728 time: 300000
729 })) as ButtonInteraction | StringSelectMenuInteraction;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500730 } catch (e) {
731 closed = true;
732 break;
733 }
734
Skyler Greyda16adf2023-03-05 10:22:12 +0000735 if (i.isButton()) {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500736 await i.deferUpdate();
737 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000738 case "back": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500739 closed = true;
740 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000741 }
742 case "everyone": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500743 current.everyone = !current.everyone;
TheCodedProf35e73712023-03-10 17:35:35 -0500744 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500745 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000746 }
747 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500748 current.roles = !current.roles;
TheCodedProf35e73712023-03-10 17:35:35 -0500749 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500750 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000751 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500752 }
753 } else {
754 switch (i.customId) {
PineaFanb0d0c242023-02-05 10:59:45 +0000755 case "toEdit": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500756 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000757 case "mass": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000758 await interaction.editReply({
759 embeds: [
760 new EmojiEmbed()
761 .setTitle("Word Filter")
762 .setDescription("Modal opened. If you can't see it, click back and try again.")
763 .setStatus("Success")
764 .setEmoji("GUILD.SETTINGS.GREEN")
765 ],
766 components: [
767 new ActionRowBuilder<ButtonBuilder>().addComponents(
768 new ButtonBuilder()
769 .setLabel("Back")
770 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
771 .setStyle(ButtonStyle.Primary)
772 .setCustomId("back")
773 )
774 ]
775 });
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500776 const modal = new ModalBuilder()
777 .setTitle("Mass Mention Amount")
778 .setCustomId("mass")
779 .addComponents(
Skyler Greyda16adf2023-03-05 10:22:12 +0000780 new ActionRowBuilder<TextInputBuilder>().addComponents(
781 new TextInputBuilder()
782 .setCustomId("mass")
783 .setPlaceholder("Amount")
784 .setMinLength(1)
785 .setMaxLength(3)
786 .setStyle(TextInputStyle.Short)
787 )
788 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500789 await i.showModal(modal);
790 let out;
791 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500792 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500793 } catch (e) {
794 break;
795 }
796 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000797 if (out.isButton()) break;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500798 current.mass = parseInt(out.fields.getTextInputValue("mass"));
TheCodedProf35e73712023-03-10 17:35:35 -0500799 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500800 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000801 }
802 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500803 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000804 current.allowed.rolesToMention = await toSelectMenu(
805 interaction,
806 m,
807 current.allowed.rolesToMention,
808 "role",
809 "Mention Settings"
810 );
TheCodedProf35e73712023-03-10 17:35:35 -0500811 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500812 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000813 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500814 }
815 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000816 }
817 case "allowed": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500818 await i.deferUpdate();
819 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000820 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000821 current.allowed.users = await toSelectMenu(
822 interaction,
823 m,
824 current.allowed.users,
825 "member",
826 "Mention Settings"
827 );
TheCodedProf35e73712023-03-10 17:35:35 -0500828 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500829 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000830 }
831 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000832 current.allowed.roles = await toSelectMenu(
833 interaction,
834 m,
835 current.allowed.roles,
836 "role",
837 "Mention Settings"
838 );
TheCodedProf35e73712023-03-10 17:35:35 -0500839 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500840 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000841 }
842 case "channels": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000843 current.allowed.channels = await toSelectMenu(
844 interaction,
845 m,
846 current.allowed.channels,
847 "channel",
848 "Mention Settings"
849 );
TheCodedProf35e73712023-03-10 17:35:35 -0500850 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500851 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000852 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500853 }
854 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000855 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500856 }
857 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000858 } while (!closed);
859 return current;
860};
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500861
Skyler Greyda16adf2023-03-05 10:22:12 +0000862const cleanMenu = async (
863 interaction: StringSelectMenuInteraction,
864 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500865 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000866 current?: {
867 channels?: string[];
868 allowed?: {
869 roles: string[];
870 users: string[];
871 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500872 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000873): Promise<{
874 channels: string[];
TheCodedProfad0b8202023-02-14 14:27:09 -0500875 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000876 roles: string[];
877 users: string[];
878 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500879}> => {
880 let closed = false;
Skyler Greyda16adf2023-03-05 10:22:12 +0000881 if (!current) current = { channels: [], allowed: { roles: [], users: [] } };
882 if (!current.channels) current.channels = [];
883 if (!current.allowed) current.allowed = { roles: [], users: [] };
TheCodedProfad0b8202023-02-14 14:27:09 -0500884
Skyler Greyda16adf2023-03-05 10:22:12 +0000885 const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(
886 new ChannelSelectMenuBuilder().setCustomId("toAdd").setPlaceholder("Select a channel")
887 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500888
Skyler Greyda16adf2023-03-05 10:22:12 +0000889 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
890 new StringSelectMenuBuilder()
891 .setCustomId("allowed")
892 .setPlaceholder("Edit exceptions")
893 .addOptions(
894 new StringSelectMenuOptionBuilder()
895 .setLabel("Users")
896 .setDescription("Users that are unaffected by the mention filter")
897 .setValue("users"),
898 new StringSelectMenuOptionBuilder()
899 .setLabel("Roles")
900 .setDescription("Roles that are unaffected by the mention filter")
901 .setValue("roles")
902 )
903 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500904
905 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000906 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
907 new ButtonBuilder()
908 .setCustomId("back")
909 .setLabel("Back")
910 .setStyle(ButtonStyle.Primary)
911 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
912 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500913
914 const embed = new EmojiEmbed()
915 .setTitle("Clean Settings")
916 .setEmoji("GUILD.SETTINGS.GREEN")
917 .setDescription(
918 `Current clean channels:\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000919 `${
920 current.channels.length > 0
921 ? listToAndMore(
922 current.channels.map((c) => `<#${c}>`),
923 10
924 )
925 : "None"
926 }\n\n`
TheCodedProfad0b8202023-02-14 14:27:09 -0500927 )
TheCodedProf35e73712023-03-10 17:35:35 -0500928 .setStatus("Success")
929 .setFooter({
930 text: unsavedChanges ? "No changes made" : "Changes not saved"
931 });
TheCodedProfad0b8202023-02-14 14:27:09 -0500932
Skyler Greyda16adf2023-03-05 10:22:12 +0000933 await interaction.editReply({ embeds: [embed], components: [channelMenu, allowedMenu, buttons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500934
935 let i: ButtonInteraction | ChannelSelectMenuInteraction;
936 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000937 i = (await m.awaitMessageComponent({
938 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
939 time: 300000
940 })) as ButtonInteraction | ChannelSelectMenuInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500941 } catch (e) {
942 closed = true;
943 break;
944 }
945 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000946 if (i.isButton()) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500947 switch (i.customId) {
948 case "back": {
949 closed = true;
950 break;
951 }
952 }
953 } else {
954 switch (i.customId) {
955 case "toAdd": {
TheCodedProf1807fb32023-02-20 14:33:48 -0500956 const channelEmbed = new EmojiEmbed()
TheCodedProfad0b8202023-02-14 14:27:09 -0500957 .setTitle("Clean Settings")
958 .setDescription(`Editing <#${i.values[0]}>`)
959 .setEmoji("GUILD.SETTINGS.GREEN")
Skyler Greyda16adf2023-03-05 10:22:12 +0000960 .setStatus("Success");
961 const channelButtons = new ActionRowBuilder<ButtonBuilder>().addComponents(
962 new ButtonBuilder()
963 .setCustomId("back")
964 .setLabel("Back")
965 .setStyle(ButtonStyle.Primary)
966 .setEmoji(getEmojiByName("CONTROL.LEFT", "id")),
967 new ButtonBuilder()
968 .setCustomId("switch")
969 .setLabel(current.channels.includes(i.values[0]!) ? "Remove" : "Add")
970 .setStyle(
971 current.channels.includes(i.values[0]!) ? ButtonStyle.Danger : ButtonStyle.Success
972 )
973 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500974
Skyler Greyda16adf2023-03-05 10:22:12 +0000975 await i.editReply({ embeds: [channelEmbed], components: [channelButtons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500976 let j: ButtonInteraction;
977 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000978 j = (await m.awaitMessageComponent({
979 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
980 time: 300000
981 })) as ButtonInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500982 } catch (e) {
983 closed = true;
984 break;
985 }
986 await j.deferUpdate();
987 switch (j.customId) {
988 case "back": {
989 break;
990 }
991 case "switch": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000992 if (current.channels.includes(i.values[0]!)) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500993 current.channels.splice(current.channels.indexOf(i.values[0]!), 1);
994 } else {
995 current.channels.push(i.values[0]!);
996 }
997 }
998 }
TheCodedProf35e73712023-03-10 17:35:35 -0500999 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001000 break;
1001 }
1002 case "allowed": {
1003 switch (i.values[0]) {
1004 case "users": {
Skyler Greyda16adf2023-03-05 10:22:12 +00001005 current.allowed.users = await toSelectMenu(
1006 interaction,
1007 m,
1008 current.allowed.users,
1009 "member",
1010 "Mention Settings"
1011 );
TheCodedProf35e73712023-03-10 17:35:35 -05001012 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001013 break;
1014 }
1015 case "roles": {
Skyler Greyda16adf2023-03-05 10:22:12 +00001016 current.allowed.roles = await toSelectMenu(
1017 interaction,
1018 m,
1019 current.allowed.roles,
1020 "role",
1021 "Mention Settings"
1022 );
TheCodedProf35e73712023-03-10 17:35:35 -05001023 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -05001024 break;
1025 }
1026 }
1027 break;
1028 }
1029 }
1030 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001031 } while (!closed);
TheCodedProfad0b8202023-02-14 14:27:09 -05001032
TheCodedProf1807fb32023-02-20 14:33:48 -05001033 return current as {
Skyler Greyda16adf2023-03-05 10:22:12 +00001034 channels: string[];
TheCodedProf1807fb32023-02-20 14:33:48 -05001035 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +00001036 roles: string[];
1037 users: string[];
1038 };
TheCodedProf1807fb32023-02-20 14:33:48 -05001039 };
Skyler Greyda16adf2023-03-05 10:22:12 +00001040};
TheCodedProfad0b8202023-02-14 14:27:09 -05001041
TheCodedProf8b3da212023-02-02 15:09:55 -05001042const callback = async (interaction: CommandInteraction): Promise<void> => {
1043 if (!interaction.guild) return;
Skyler Greyda16adf2023-03-05 10:22:12 +00001044 const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
TheCodedProf35e73712023-03-10 17:35:35 -05001045 let config = (await client.database.guilds.read(interaction.guild.id)).filters;
TheCodedProf8b3da212023-02-02 15:09:55 -05001046
1047 let closed = false;
1048
TheCodedProf35e73712023-03-10 17:35:35 -05001049 let current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001050 do {
TheCodedProf35e73712023-03-10 17:35:35 -05001051 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProfca29ebb2023-03-10 17:40:09 -05001052 new ButtonBuilder()
1053 .setCustomId("save")
1054 .setLabel("Save")
1055 .setStyle(ButtonStyle.Success)
1056 .setDisabled(_.isEqual(config, current))
TheCodedProf35e73712023-03-10 17:35:35 -05001057 );
Skyler Greyda16adf2023-03-05 10:22:12 +00001058 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
1059 new StringSelectMenuBuilder()
1060 .setCustomId("filter")
1061 .setPlaceholder("Select a filter to edit")
1062 .addOptions(
1063 new StringSelectMenuOptionBuilder()
1064 .setLabel("Invites")
1065 .setDescription("Automatically delete messages containing server invites")
1066 .setValue("invites"),
1067 new StringSelectMenuOptionBuilder()
1068 .setLabel("Mentions")
1069 .setDescription("Deletes messages with excessive mentions")
1070 .setValue("mentions"),
1071 new StringSelectMenuOptionBuilder()
1072 .setLabel("Words")
1073 .setDescription("Delete messages containing filtered words")
1074 .setValue("words"),
1075 new StringSelectMenuOptionBuilder()
1076 .setLabel("Malware")
1077 .setDescription("Automatically delete files and links containing malware")
1078 .setValue("malware"),
1079 new StringSelectMenuOptionBuilder()
1080 .setLabel("Images")
1081 .setDescription("Checks performed on images (NSFW, size checking, etc.)")
1082 .setValue("images"),
1083 new StringSelectMenuOptionBuilder()
1084 .setLabel("Clean")
1085 .setDescription("Automatically delete new messages in specific channels")
1086 .setValue("clean")
1087 )
1088 );
TheCodedProf8b3da212023-02-02 15:09:55 -05001089
1090 const embed = new EmojiEmbed()
1091 .setTitle("Automod Settings")
1092 .setDescription(
TheCodedProf486bca32023-02-02 16:49:44 -05001093 `${emojiFromBoolean(config.invite.enabled)} **Invites**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +00001094 `${emojiFromBoolean(
1095 config.pings.everyone || config.pings.mass > 0 || config.pings.roles
1096 )} **Mentions**\n` +
1097 `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` +
1098 `${emojiFromBoolean(config.malware)} **Malware**\n` +
1099 `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**\n` +
1100 `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n`
TheCodedProf8b3da212023-02-02 15:09:55 -05001101 )
TheCodedProf486bca32023-02-02 16:49:44 -05001102 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -05001103 .setEmoji("GUILD.SETTINGS.GREEN")
1104 .setFooter({
1105 text: _.isEqual(config, current) ? "No changes made" : "Changes not saved"
1106 });
TheCodedProf8b3da212023-02-02 15:09:55 -05001107
Skyler Greyda16adf2023-03-05 10:22:12 +00001108 await interaction.editReply({ embeds: [embed], components: [selectMenu, button] });
TheCodedProf8b3da212023-02-02 15:09:55 -05001109
1110 let i: StringSelectMenuInteraction | ButtonInteraction;
1111 try {
Skyler Greyda16adf2023-03-05 10:22:12 +00001112 i = (await m.awaitMessageComponent({
1113 filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
1114 time: 300000
1115 })) as StringSelectMenuInteraction | ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -05001116 } catch (e) {
1117 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +00001118 continue;
TheCodedProf8b3da212023-02-02 15:09:55 -05001119 }
TheCodedProf35e73712023-03-10 17:35:35 -05001120 await i.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -05001121 if (i.isButton()) {
TheCodedProf35e73712023-03-10 17:35:35 -05001122 await client.database.guilds.write(interaction.guild.id, { filters: current });
Skyler Grey16ecb172023-03-05 07:30:32 +00001123 await client.memory.forceUpdate(interaction.guild.id);
TheCodedProf35e73712023-03-10 17:35:35 -05001124 config = current;
1125 current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001126 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +00001127 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +00001128 case "invites": {
TheCodedProf35e73712023-03-10 17:35:35 -05001129 config.invite = await inviteMenu(i, m, _.isEqual(config, current), config.invite);
TheCodedProf8b3da212023-02-02 15:09:55 -05001130 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001131 }
1132 case "mentions": {
TheCodedProf35e73712023-03-10 17:35:35 -05001133 config.pings = await mentionMenu(i, m, _.isEqual(config, current), config.pings);
TheCodedProf8b3da212023-02-02 15:09:55 -05001134 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001135 }
1136 case "words": {
TheCodedProf35e73712023-03-10 17:35:35 -05001137 config.wordFilter = await wordMenu(i, m, _.isEqual(config, current), config.wordFilter);
TheCodedProf8b3da212023-02-02 15:09:55 -05001138 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001139 }
1140 case "malware": {
TheCodedProf8b3da212023-02-02 15:09:55 -05001141 config.malware = !config.malware;
1142 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001143 }
1144 case "images": {
TheCodedProf35e73712023-03-10 17:35:35 -05001145 const next = await imageMenu(i, m, _.isEqual(config, current), config.images);
PineaFanb0d0c242023-02-05 10:59:45 +00001146 config.images = next;
TheCodedProf8b3da212023-02-02 15:09:55 -05001147 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001148 }
TheCodedProfad0b8202023-02-14 14:27:09 -05001149 case "clean": {
TheCodedProf35e73712023-03-10 17:35:35 -05001150 const next = await cleanMenu(i, m, _.isEqual(config, current), config.clean);
TheCodedProfad0b8202023-02-14 14:27:09 -05001151 config.clean = next;
1152 break;
1153 }
TheCodedProf8b3da212023-02-02 15:09:55 -05001154 }
1155 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001156 } while (!closed);
1157 await interaction.deleteReply();
TheCodedProf8b3da212023-02-02 15:09:55 -05001158};
1159
1160const check = (interaction: CommandInteraction, _partial: boolean = false) => {
1161 const member = interaction.member as Discord.GuildMember;
1162 if (!member.permissions.has("ManageMessages"))
1163 return "You must have the *Manage Messages* permission to use this command";
1164 return true;
1165};
1166
1167export { command };
1168export { callback };
1169export { check };