blob: a854fc539985b8109c0a419aebb728d227eb0fbf [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()
760 .setCustomId("mass")
761 .setPlaceholder("Amount")
762 .setMinLength(1)
763 .setMaxLength(3)
764 .setStyle(TextInputStyle.Short)
765 )
766 );
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500767 await i.showModal(modal);
768 let out;
769 try {
TheCodedProf01cba762023-02-18 15:55:05 -0500770 out = await modalInteractionCollector(m, interaction.user);
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500771 } catch (e) {
772 break;
773 }
774 if (!out) break;
Skyler Greyda16adf2023-03-05 10:22:12 +0000775 if (out.isButton()) break;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500776 current.mass = parseInt(out.fields.getTextInputValue("mass"));
TheCodedProf35e73712023-03-10 17:35:35 -0500777 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500778 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000779 }
780 case "roles": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500781 await i.deferUpdate();
TheCodedProf36d99b32023-04-07 14:54:01 -0400782 current.allowed.rolesToMention = _.cloneDeep(
783 await toSelectMenu(
784 interaction,
785 m,
786 current.allowed.rolesToMention,
787 "role",
788 "Mention Settings"
789 )
790 );
TheCodedProf35e73712023-03-10 17:35:35 -0500791 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500792 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000793 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500794 }
795 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000796 }
797 case "allowed": {
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500798 await i.deferUpdate();
799 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +0000800 case "users": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400801 current.allowed.users = _.cloneDeep(
802 await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings")
803 );
TheCodedProf35e73712023-03-10 17:35:35 -0500804 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500805 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000806 }
807 case "roles": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400808 current.allowed.roles = _.cloneDeep(
809 await toSelectMenu(interaction, m, current.allowed.roles, "role", "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 }
814 case "channels": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400815 current.allowed.channels = _.cloneDeep(
816 await toSelectMenu(
817 interaction,
818 m,
819 current.allowed.channels,
820 "channel",
821 "Mention Settings"
822 )
823 );
TheCodedProf35e73712023-03-10 17:35:35 -0500824 unsavedChanges = true;
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500825 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000826 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500827 }
828 break;
PineaFanb0d0c242023-02-05 10:59:45 +0000829 }
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500830 }
831 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000832 } while (!closed);
833 return current;
834};
TheCodedProf5b53a8c2023-02-03 15:40:26 -0500835
Skyler Greyda16adf2023-03-05 10:22:12 +0000836const cleanMenu = async (
837 interaction: StringSelectMenuInteraction,
838 m: Message,
TheCodedProf35e73712023-03-10 17:35:35 -0500839 unsavedChanges: boolean,
Skyler Greyda16adf2023-03-05 10:22:12 +0000840 current?: {
841 channels?: string[];
842 allowed?: {
843 roles: string[];
844 users: string[];
845 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500846 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000847): Promise<{
848 channels: string[];
TheCodedProfad0b8202023-02-14 14:27:09 -0500849 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000850 roles: string[];
851 users: string[];
852 };
TheCodedProfad0b8202023-02-14 14:27:09 -0500853}> => {
854 let closed = false;
Skyler Greyda16adf2023-03-05 10:22:12 +0000855 if (!current) current = { channels: [], allowed: { roles: [], users: [] } };
856 if (!current.channels) current.channels = [];
857 if (!current.allowed) current.allowed = { roles: [], users: [] };
TheCodedProfad0b8202023-02-14 14:27:09 -0500858
Skyler Greyda16adf2023-03-05 10:22:12 +0000859 const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(
860 new ChannelSelectMenuBuilder().setCustomId("toAdd").setPlaceholder("Select a channel")
861 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500862
Skyler Greyda16adf2023-03-05 10:22:12 +0000863 const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
864 new StringSelectMenuBuilder()
865 .setCustomId("allowed")
866 .setPlaceholder("Edit exceptions")
867 .addOptions(
868 new StringSelectMenuOptionBuilder()
869 .setLabel("Users")
870 .setDescription("Users that are unaffected by the mention filter")
871 .setValue("users"),
872 new StringSelectMenuOptionBuilder()
873 .setLabel("Roles")
874 .setDescription("Roles that are unaffected by the mention filter")
875 .setValue("roles")
876 )
877 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500878
879 do {
Skyler Greyda16adf2023-03-05 10:22:12 +0000880 const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
881 new ButtonBuilder()
882 .setCustomId("back")
883 .setLabel("Back")
884 .setStyle(ButtonStyle.Primary)
885 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
886 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500887
888 const embed = new EmojiEmbed()
889 .setTitle("Clean Settings")
890 .setEmoji("GUILD.SETTINGS.GREEN")
891 .setDescription(
892 `Current clean channels:\n\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000893 `${
894 current.channels.length > 0
895 ? listToAndMore(
896 current.channels.map((c) => `<#${c}>`),
897 10
898 )
899 : "None"
900 }\n\n`
TheCodedProfad0b8202023-02-14 14:27:09 -0500901 )
TheCodedProf35e73712023-03-10 17:35:35 -0500902 .setStatus("Success")
903 .setFooter({
904 text: unsavedChanges ? "No changes made" : "Changes not saved"
905 });
TheCodedProfad0b8202023-02-14 14:27:09 -0500906
Skyler Greyda16adf2023-03-05 10:22:12 +0000907 await interaction.editReply({ embeds: [embed], components: [channelMenu, allowedMenu, buttons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500908
909 let i: ButtonInteraction | ChannelSelectMenuInteraction;
910 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000911 i = (await m.awaitMessageComponent({
912 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
913 time: 300000
914 })) as ButtonInteraction | ChannelSelectMenuInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500915 } catch (e) {
916 closed = true;
917 break;
918 }
919 await i.deferUpdate();
Skyler Greyda16adf2023-03-05 10:22:12 +0000920 if (i.isButton()) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500921 switch (i.customId) {
922 case "back": {
923 closed = true;
924 break;
925 }
926 }
927 } else {
928 switch (i.customId) {
929 case "toAdd": {
TheCodedProf1807fb32023-02-20 14:33:48 -0500930 const channelEmbed = new EmojiEmbed()
TheCodedProfad0b8202023-02-14 14:27:09 -0500931 .setTitle("Clean Settings")
932 .setDescription(`Editing <#${i.values[0]}>`)
933 .setEmoji("GUILD.SETTINGS.GREEN")
Skyler Greyda16adf2023-03-05 10:22:12 +0000934 .setStatus("Success");
935 const channelButtons = new ActionRowBuilder<ButtonBuilder>().addComponents(
936 new ButtonBuilder()
937 .setCustomId("back")
938 .setLabel("Back")
939 .setStyle(ButtonStyle.Primary)
940 .setEmoji(getEmojiByName("CONTROL.LEFT", "id")),
941 new ButtonBuilder()
942 .setCustomId("switch")
943 .setLabel(current.channels.includes(i.values[0]!) ? "Remove" : "Add")
944 .setStyle(
945 current.channels.includes(i.values[0]!) ? ButtonStyle.Danger : ButtonStyle.Success
946 )
947 );
TheCodedProfad0b8202023-02-14 14:27:09 -0500948
Skyler Greyda16adf2023-03-05 10:22:12 +0000949 await i.editReply({ embeds: [channelEmbed], components: [channelButtons] });
TheCodedProfad0b8202023-02-14 14:27:09 -0500950 let j: ButtonInteraction;
951 try {
Skyler Greyda16adf2023-03-05 10:22:12 +0000952 j = (await m.awaitMessageComponent({
953 filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id,
954 time: 300000
955 })) as ButtonInteraction;
TheCodedProfad0b8202023-02-14 14:27:09 -0500956 } catch (e) {
957 closed = true;
958 break;
959 }
960 await j.deferUpdate();
961 switch (j.customId) {
962 case "back": {
963 break;
964 }
965 case "switch": {
Skyler Greyda16adf2023-03-05 10:22:12 +0000966 if (current.channels.includes(i.values[0]!)) {
TheCodedProfad0b8202023-02-14 14:27:09 -0500967 current.channels.splice(current.channels.indexOf(i.values[0]!), 1);
968 } else {
969 current.channels.push(i.values[0]!);
970 }
971 }
972 }
TheCodedProf35e73712023-03-10 17:35:35 -0500973 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500974 break;
975 }
976 case "allowed": {
977 switch (i.values[0]) {
978 case "users": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400979 current.allowed.users = _.cloneDeep(
980 await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings")
981 );
TheCodedProf35e73712023-03-10 17:35:35 -0500982 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500983 break;
984 }
985 case "roles": {
TheCodedProf36d99b32023-04-07 14:54:01 -0400986 current.allowed.roles = _.cloneDeep(
987 await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings")
988 );
TheCodedProf35e73712023-03-10 17:35:35 -0500989 unsavedChanges = true;
TheCodedProfad0b8202023-02-14 14:27:09 -0500990 break;
991 }
992 }
993 break;
994 }
995 }
996 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000997 } while (!closed);
TheCodedProfad0b8202023-02-14 14:27:09 -0500998
TheCodedProf1807fb32023-02-20 14:33:48 -0500999 return current as {
Skyler Greyda16adf2023-03-05 10:22:12 +00001000 channels: string[];
TheCodedProf1807fb32023-02-20 14:33:48 -05001001 allowed: {
Skyler Greyda16adf2023-03-05 10:22:12 +00001002 roles: string[];
1003 users: string[];
1004 };
TheCodedProf1807fb32023-02-20 14:33:48 -05001005 };
Skyler Greyda16adf2023-03-05 10:22:12 +00001006};
TheCodedProfad0b8202023-02-14 14:27:09 -05001007
TheCodedProf8b3da212023-02-02 15:09:55 -05001008const callback = async (interaction: CommandInteraction): Promise<void> => {
1009 if (!interaction.guild) return;
Skyler Greyda16adf2023-03-05 10:22:12 +00001010 const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
TheCodedProf35e73712023-03-10 17:35:35 -05001011 let config = (await client.database.guilds.read(interaction.guild.id)).filters;
TheCodedProf8b3da212023-02-02 15:09:55 -05001012
1013 let closed = false;
1014
TheCodedProf35e73712023-03-10 17:35:35 -05001015 let current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001016 do {
TheCodedProf35e73712023-03-10 17:35:35 -05001017 const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProfca29ebb2023-03-10 17:40:09 -05001018 new ButtonBuilder()
1019 .setCustomId("save")
1020 .setLabel("Save")
1021 .setStyle(ButtonStyle.Success)
1022 .setDisabled(_.isEqual(config, current))
TheCodedProf35e73712023-03-10 17:35:35 -05001023 );
Skyler Greyda16adf2023-03-05 10:22:12 +00001024 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
1025 new StringSelectMenuBuilder()
1026 .setCustomId("filter")
1027 .setPlaceholder("Select a filter to edit")
1028 .addOptions(
1029 new StringSelectMenuOptionBuilder()
1030 .setLabel("Invites")
1031 .setDescription("Automatically delete messages containing server invites")
1032 .setValue("invites"),
1033 new StringSelectMenuOptionBuilder()
1034 .setLabel("Mentions")
1035 .setDescription("Deletes messages with excessive mentions")
1036 .setValue("mentions"),
1037 new StringSelectMenuOptionBuilder()
1038 .setLabel("Words")
1039 .setDescription("Delete messages containing filtered words")
1040 .setValue("words"),
1041 new StringSelectMenuOptionBuilder()
1042 .setLabel("Malware")
1043 .setDescription("Automatically delete files and links containing malware")
1044 .setValue("malware"),
1045 new StringSelectMenuOptionBuilder()
1046 .setLabel("Images")
1047 .setDescription("Checks performed on images (NSFW, size checking, etc.)")
1048 .setValue("images"),
1049 new StringSelectMenuOptionBuilder()
1050 .setLabel("Clean")
1051 .setDescription("Automatically delete new messages in specific channels")
1052 .setValue("clean")
1053 )
1054 );
TheCodedProf8b3da212023-02-02 15:09:55 -05001055
1056 const embed = new EmojiEmbed()
1057 .setTitle("Automod Settings")
1058 .setDescription(
TheCodedProf486bca32023-02-02 16:49:44 -05001059 `${emojiFromBoolean(config.invite.enabled)} **Invites**\n` +
Skyler Greyda16adf2023-03-05 10:22:12 +00001060 `${emojiFromBoolean(
1061 config.pings.everyone || config.pings.mass > 0 || config.pings.roles
1062 )} **Mentions**\n` +
1063 `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` +
1064 `${emojiFromBoolean(config.malware)} **Malware**\n` +
1065 `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**\n` +
1066 `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n`
TheCodedProf8b3da212023-02-02 15:09:55 -05001067 )
TheCodedProf486bca32023-02-02 16:49:44 -05001068 .setStatus("Success")
TheCodedProf35e73712023-03-10 17:35:35 -05001069 .setEmoji("GUILD.SETTINGS.GREEN")
1070 .setFooter({
1071 text: _.isEqual(config, current) ? "No changes made" : "Changes not saved"
1072 });
TheCodedProf8b3da212023-02-02 15:09:55 -05001073
Skyler Greyda16adf2023-03-05 10:22:12 +00001074 await interaction.editReply({ embeds: [embed], components: [selectMenu, button] });
TheCodedProf8b3da212023-02-02 15:09:55 -05001075
1076 let i: StringSelectMenuInteraction | ButtonInteraction;
1077 try {
Skyler Greyda16adf2023-03-05 10:22:12 +00001078 i = (await m.awaitMessageComponent({
1079 filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
1080 time: 300000
1081 })) as StringSelectMenuInteraction | ButtonInteraction;
TheCodedProf8b3da212023-02-02 15:09:55 -05001082 } catch (e) {
1083 closed = true;
PineaFanb0d0c242023-02-05 10:59:45 +00001084 continue;
TheCodedProf8b3da212023-02-02 15:09:55 -05001085 }
TheCodedProf35e73712023-03-10 17:35:35 -05001086 await i.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -05001087 if (i.isButton()) {
TheCodedProf35e73712023-03-10 17:35:35 -05001088 await client.database.guilds.write(interaction.guild.id, { filters: current });
Skyler Grey16ecb172023-03-05 07:30:32 +00001089 await client.memory.forceUpdate(interaction.guild.id);
TheCodedProf35e73712023-03-10 17:35:35 -05001090 config = current;
1091 current = _.cloneDeep(config);
TheCodedProf8b3da212023-02-02 15:09:55 -05001092 } else {
Skyler Greyda16adf2023-03-05 10:22:12 +00001093 switch (i.values[0]) {
PineaFanb0d0c242023-02-05 10:59:45 +00001094 case "invites": {
TheCodedProf35e73712023-03-10 17:35:35 -05001095 config.invite = await inviteMenu(i, m, _.isEqual(config, current), config.invite);
TheCodedProf8b3da212023-02-02 15:09:55 -05001096 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001097 }
1098 case "mentions": {
TheCodedProf35e73712023-03-10 17:35:35 -05001099 config.pings = await mentionMenu(i, m, _.isEqual(config, current), config.pings);
TheCodedProf8b3da212023-02-02 15:09:55 -05001100 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001101 }
1102 case "words": {
TheCodedProf35e73712023-03-10 17:35:35 -05001103 config.wordFilter = await wordMenu(i, m, _.isEqual(config, current), config.wordFilter);
TheCodedProf8b3da212023-02-02 15:09:55 -05001104 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001105 }
1106 case "malware": {
TheCodedProf8b3da212023-02-02 15:09:55 -05001107 config.malware = !config.malware;
1108 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001109 }
1110 case "images": {
TheCodedProf35e73712023-03-10 17:35:35 -05001111 const next = await imageMenu(i, m, _.isEqual(config, current), config.images);
PineaFanb0d0c242023-02-05 10:59:45 +00001112 config.images = next;
TheCodedProf8b3da212023-02-02 15:09:55 -05001113 break;
PineaFanb0d0c242023-02-05 10:59:45 +00001114 }
TheCodedProfad0b8202023-02-14 14:27:09 -05001115 case "clean": {
TheCodedProf35e73712023-03-10 17:35:35 -05001116 const next = await cleanMenu(i, m, _.isEqual(config, current), config.clean);
TheCodedProfad0b8202023-02-14 14:27:09 -05001117 config.clean = next;
1118 break;
1119 }
TheCodedProf8b3da212023-02-02 15:09:55 -05001120 }
1121 }
Skyler Greyda16adf2023-03-05 10:22:12 +00001122 } while (!closed);
1123 await interaction.deleteReply();
TheCodedProf8b3da212023-02-02 15:09:55 -05001124};
1125
1126const check = (interaction: CommandInteraction, _partial: boolean = false) => {
1127 const member = interaction.member as Discord.GuildMember;
1128 if (!member.permissions.has("ManageMessages"))
1129 return "You must have the *Manage Messages* permission to use this command";
1130 return true;
1131};
1132
1133export { command };
1134export { callback };
1135export { check };