| import type Discord from "discord.js"; |
| import { ActionRowBuilder, |
| AnySelectMenuInteraction, |
| APIMessageComponentEmoji, |
| ButtonBuilder, |
| ButtonInteraction, |
| ButtonStyle, |
| ChannelSelectMenuBuilder, |
| ChannelSelectMenuInteraction, |
| CommandInteraction, |
| Interaction, |
| Message, |
| MessageComponentInteraction, |
| ModalBuilder, |
| ModalSubmitInteraction, |
| RoleSelectMenuBuilder, |
| RoleSelectMenuInteraction, |
| StringSelectMenuBuilder, |
| StringSelectMenuInteraction, |
| StringSelectMenuOptionBuilder, |
| TextInputBuilder, |
| TextInputStyle, |
| UserSelectMenuBuilder, |
| UserSelectMenuInteraction |
| } from "discord.js"; |
| import type { SlashCommandSubcommandBuilder } from "discord.js"; |
| import { LoadingEmbed } from "../../utils/defaults.js"; |
| import EmojiEmbed from "../../utils/generateEmojiEmbed.js"; |
| import client from "../../utils/client.js"; |
| import getEmojiByName from "../../utils/getEmojiByName.js"; |
| import { modalInteractionCollector } from "../../utils/dualCollector.js"; |
| |
| |
| const command = (builder: SlashCommandSubcommandBuilder) => |
| builder.setName("automod").setDescription("Setting for automatic moderation features"); |
| |
| |
| const emojiFromBoolean = (bool: boolean, id?: string) => bool ? getEmojiByName("CONTROL.TICK", id) : getEmojiByName("CONTROL.CROSS", id); |
| |
| const listToAndMore = (list: string[], max: number) => { |
| // PineappleFan, Coded, Mini (and 10 more) |
| if(list.length > max) { |
| return list.slice(0, max).join(", ") + ` (and ${list.length - max} more)`; |
| } |
| return list.join(", "); |
| } |
| |
| const toSelectMenu = async (interaction: StringSelectMenuInteraction, m: Message, ids: string[], type: "member" | "role" | "channel", title: string): Promise<string[]> => { |
| |
| const back = new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder().setCustomId("back").setLabel("Back").setStyle(ButtonStyle.Secondary).setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)); |
| let closed; |
| do { |
| let render: string[] = [] |
| let mapped: string[] = []; |
| let menu: UserSelectMenuBuilder | RoleSelectMenuBuilder | ChannelSelectMenuBuilder; |
| switch(type) { |
| case "member": { |
| menu = new UserSelectMenuBuilder().setCustomId("user").setPlaceholder("Select users").setMaxValues(25); |
| mapped = await Promise.all(ids.map(async (id) => { return (await client.users.fetch(id).then(user => user.tag)) || "Unknown User" })); |
| render = ids.map(id => client.logger.renderUser(id)) |
| break; |
| } |
| case "role": { |
| menu = new RoleSelectMenuBuilder().setCustomId("role").setPlaceholder("Select roles").setMaxValues(25); |
| mapped = await Promise.all(ids.map(async (id) => { return (await interaction.guild!.roles.fetch(id).then(role => role?.name ?? "Unknown Role"))})); |
| render = ids.map(id => client.logger.renderRole(id, interaction.guild!)) |
| break; |
| } |
| case "channel": { |
| menu = new ChannelSelectMenuBuilder().setCustomId("channel").setPlaceholder("Select channels").setMaxValues(25); |
| mapped = await Promise.all(ids.map(async (id) => { return (await interaction.guild!.channels.fetch(id).then(channel => channel?.name ?? "Unknown Role")) })); |
| render = ids.map(id => client.logger.renderChannel(id)) |
| break; |
| } |
| } |
| const removeOptions = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("remove") |
| .setPlaceholder("Remove") |
| .addOptions(mapped.map((name, i) => new StringSelectMenuOptionBuilder().setLabel(name).setValue(ids[i]!))) |
| .setDisabled(ids.length === 0) |
| ); |
| |
| const embed = new EmojiEmbed() |
| .setTitle(title) |
| .setEmoji(getEmojiByName("GUILD.SETTINGS.GREEN")) |
| .setDescription(`Select ${type}s:\n\nCurrent:\n` + (render.length > 0 ? render.join("\n") : "None")) |
| .setStatus("Success"); |
| const components: ActionRowBuilder< |
| StringSelectMenuBuilder | |
| ButtonBuilder | |
| ChannelSelectMenuBuilder | |
| UserSelectMenuBuilder | |
| RoleSelectMenuBuilder |
| >[] = [new ActionRowBuilder<typeof menu>().addComponents(menu)] |
| if(ids.length > 0) components.push(removeOptions); |
| components.push(back); |
| |
| await interaction.editReply({embeds: [embed], components: components}) |
| |
| let i: AnySelectMenuInteraction | ButtonInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: i => i.user.id === interaction.user.id, time: 300000}); |
| } catch(e) { |
| closed = true; |
| continue; |
| } |
| |
| if(i.isButton()) { |
| await i.deferUpdate(); |
| if(i.customId === "back") { |
| closed = true; |
| break; |
| } |
| } else if(i.isStringSelectMenu()) { |
| await i.deferUpdate(); |
| if(i.customId === "remove") { |
| ids = ids.filter(id => id !== (i as StringSelectMenuInteraction).values[0]); |
| if(ids.length === 0) { |
| menu.data.disabled = true; |
| } |
| } |
| } else { |
| await i.deferUpdate(); |
| if(i.customId === "user") { |
| ids = ids.concat((i as UserSelectMenuInteraction).values); |
| } else if(i.customId === "role") { |
| ids = ids.concat((i as RoleSelectMenuInteraction).values); |
| } else if(i.customId === "channel") { |
| ids = ids.concat((i as ChannelSelectMenuInteraction).values); |
| } |
| } |
| |
| } while(!closed) |
| return ids; |
| } |
| |
| const imageMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: { |
| NSFW: boolean, |
| size: boolean |
| }): Promise<{NSFW: boolean, size: boolean}> => { |
| let closed = false; |
| do { |
| const options = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Secondary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("nsfw") |
| .setLabel("NSFW") |
| .setStyle(current.NSFW ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.NSFW, "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("size") |
| .setLabel("Size") |
| .setStyle(current.size ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.size, "id") as APIMessageComponentEmoji) |
| ) |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Image Settings") |
| .setDescription( |
| `${emojiFromBoolean(current.NSFW)} **NSFW**\n` + |
| `${emojiFromBoolean(current.size)} **Size**\n` |
| ) |
| |
| await interaction.editReply({embeds: [embed], components: [options]}); |
| |
| let i: ButtonInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction; |
| } catch (e) { |
| return current; |
| } |
| await i.deferUpdate(); |
| switch(i.customId) { |
| case "back": { |
| closed = true; |
| break; |
| } |
| case "nsfw": { |
| current.NSFW = !current.NSFW; |
| break; |
| } |
| case "size": { |
| current.size = !current.size; |
| break; |
| } |
| } |
| } while(!closed); |
| return current; |
| } |
| |
| const wordMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: { |
| enabled: boolean, |
| words: {strict: string[], loose: string[]}, |
| allowed: {users: string[], roles: string[], channels: string[]} |
| }): Promise<{ |
| enabled: boolean, |
| words: {strict: string[], loose: string[]}, |
| allowed: {users: string[], roles: string[], channels: string[]} |
| }> => { |
| let closed = false; |
| do { |
| const buttons = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Secondary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("enabled") |
| .setLabel("Enabled") |
| .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji), |
| ); |
| |
| const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("edit") |
| .setPlaceholder("Edit... ") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Words") |
| .setDescription("Edit your list of words to filter") |
| .setValue("words"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Allowed Users") |
| .setDescription("Users who will be unaffected by the word filter") |
| .setValue("allowedUsers"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Allowed Roles") |
| .setDescription("Roles that will be unaffected by the word filter") |
| .setValue("allowedRoles"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Allowed Channels") |
| .setDescription("Channels where the word filter will not apply") |
| .setValue("allowedChannels") |
| ) |
| .setDisabled(!current.enabled) |
| ); |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Word Filters") |
| .setDescription( |
| `${emojiFromBoolean(current.enabled)} **Enabled**\n` + |
| `**Strict Words:** ${listToAndMore(current.words.strict, 5)}\n` + |
| `**Loose Words:** ${listToAndMore(current.words.loose, 5)}\n\n` + |
| `**Users:** ` + listToAndMore(current.allowed.users.map(user => `<@${user}>`), 5) + `\n` + |
| `**Roles:** ` + listToAndMore(current.allowed.roles.map(role => `<@&${role}>`), 5) + `\n` + |
| `**Channels:** ` + listToAndMore(current.allowed.channels.map(channel => `<#${channel}>`), 5) |
| ) |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| |
| await interaction.editReply({embeds: [embed], components: [selectMenu, buttons]}); |
| |
| let i: ButtonInteraction | StringSelectMenuInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | StringSelectMenuInteraction; |
| } catch (e) { |
| closed = true; |
| break; |
| } |
| |
| if(i.isButton()) { |
| await i.deferUpdate(); |
| switch(i.customId) { |
| case "back": { |
| closed = true; |
| break; |
| } |
| case "enabled": { |
| current.enabled = !current.enabled; |
| break; |
| } |
| } |
| } else { |
| switch(i.values[0]) { |
| case "words": { |
| await interaction.editReply({embeds: [new EmojiEmbed() |
| .setTitle("Word Filter") |
| .setDescription("Modal opened. If you can't see it, click back and try again.") |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| ], components: [new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder() |
| .setLabel("Back") |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id")) |
| .setStyle(ButtonStyle.Primary) |
| .setCustomId("back") |
| )]}) |
| const modal = new ModalBuilder() |
| .setTitle("Word Filter") |
| .setCustomId("wordFilter") |
| .addComponents( |
| new ActionRowBuilder<TextInputBuilder>() |
| .addComponents( |
| new TextInputBuilder() |
| .setCustomId("wordStrict") |
| .setLabel("Strict Words") |
| .setPlaceholder("Matches anywhere in the message, including surrounded by other characters") |
| .setValue(current.words.strict.join(", ")) |
| .setStyle(TextInputStyle.Paragraph) |
| .setRequired(false) |
| ), |
| new ActionRowBuilder<TextInputBuilder>() |
| .addComponents( |
| new TextInputBuilder() |
| .setCustomId("wordLoose") |
| .setLabel("Loose Words") |
| .setPlaceholder("Matches only if the word is by itself, surrounded by spaces or punctuation") |
| .setValue(current.words.loose.join(", ")) |
| .setStyle(TextInputStyle.Paragraph) |
| .setRequired(false) |
| ) |
| ) |
| |
| await i.showModal(modal); |
| let out; |
| try { |
| out = await modalInteractionCollector( |
| m, |
| (m: Interaction) => |
| (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId, |
| (m) => m.customId === "back" |
| ); |
| } catch (e) { |
| break; |
| } |
| if (!out) break; |
| if(out.isButton()) break; |
| current.words.strict = out.fields.getTextInputValue("wordStrict") |
| .split(",").map(s => s.trim()).filter(s => s.length > 0); |
| current.words.loose = out.fields.getTextInputValue("wordLoose") |
| .split(",").map(s => s.trim()).filter(s => s.length > 0); |
| break; |
| } |
| case "allowedUsers": { |
| await i.deferUpdate(); |
| current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Word Filter"); |
| break; |
| } |
| case "allowedRoles": { |
| await i.deferUpdate(); |
| current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Word Filter"); |
| break; |
| } |
| case "allowedChannels": { |
| await i.deferUpdate(); |
| current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Word Filter"); |
| break; |
| } |
| } |
| } |
| } while(!closed); |
| return current; |
| } |
| |
| const inviteMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: { |
| enabled: boolean, |
| allowed: {users: string[], roles: string[], channels: string[]} |
| }): Promise<{ |
| enabled: boolean, |
| allowed: {users: string[], roles: string[], channels: string[]} |
| }> => { |
| |
| let closed = false; |
| do { |
| const buttons = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Secondary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("enabled") |
| .setLabel(current.enabled ? "Enabled" : "Disabled") |
| .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji) |
| ); |
| const menu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("toEdit") |
| .setPlaceholder("Edit your allow list") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Users") |
| .setDescription("Users that are allowed to send invites") |
| .setValue("users"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Roles") |
| .setDescription("Roles that are allowed to send invites") |
| .setValue("roles"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Channels") |
| .setDescription("Channels that anyone is allowed to send invites in") |
| .setValue("channels") |
| ).setDisabled(!current.enabled) |
| ) |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Invite Settings") |
| .setDescription( |
| "Automatically deletes invites sent by users (outside of staff members and self promotion channels)" + `\n\n` + |
| `${emojiFromBoolean(current.enabled)} **${current.enabled ? "Enabled" : "Disabled"}**\n\n` + |
| `**Users:** ` + listToAndMore(current.allowed.users.map(user => `<@${user}>`), 5) + `\n` + |
| `**Roles:** ` + listToAndMore(current.allowed.roles.map(role => `<@&${role}>`), 5) + `\n` + |
| `**Channels:** ` + listToAndMore(current.allowed.channels.map(channel => `<#${channel}>`), 5) |
| ) |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| |
| |
| await interaction.editReply({embeds: [embed], components: [menu, buttons]}); |
| |
| let i: ButtonInteraction | StringSelectMenuInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | StringSelectMenuInteraction; |
| } catch (e) { |
| return current; |
| } |
| |
| if(i.isButton()) { |
| await i.deferUpdate(); |
| switch(i.customId) { |
| case "back": { |
| closed = true; |
| break; |
| } |
| case "enabled": { |
| current.enabled = !current.enabled; |
| break; |
| } |
| } |
| } else { |
| await i.deferUpdate(); |
| switch(i.values[0]) { |
| case "users": { |
| current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Invite Settings"); |
| break; |
| } |
| case "roles": { |
| current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Invite Settings"); |
| break; |
| } |
| case "channels": { |
| current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Invite Settings"); |
| break; |
| } |
| } |
| } |
| |
| } while(!closed); |
| return current; |
| } |
| |
| const mentionMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: { |
| mass: number, |
| everyone: boolean, |
| roles: boolean, |
| allowed: { |
| roles: string[], |
| rolesToMention: string[], |
| users: string[], |
| channels: string[] |
| } |
| }): Promise<{ |
| mass: number, |
| everyone: boolean, |
| roles: boolean, |
| allowed: { |
| roles: string[], |
| rolesToMention: string[], |
| users: string[], |
| channels: string[] |
| } |
| }> => { |
| let closed = false; |
| |
| do { |
| |
| const buttons = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Secondary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("everyone") |
| .setLabel(current.everyone ? "Everyone" : "No one") |
| .setStyle(current.everyone ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.everyone, "id") as APIMessageComponentEmoji), |
| new ButtonBuilder() |
| .setCustomId("roles") |
| .setLabel(current.roles ? "Roles" : "No roles") |
| .setStyle(current.roles ? ButtonStyle.Success : ButtonStyle.Danger) |
| .setEmoji(emojiFromBoolean(current.roles, "id") as APIMessageComponentEmoji) |
| ); |
| const menu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("toEdit") |
| .setPlaceholder("Edit mention settings") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Mass Mention Amount") |
| .setDescription("The amount of mentions before the bot will delete the message") |
| .setValue("mass"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Roles") |
| .setDescription("Roles that are able to be mentioned") |
| .setValue("roles"), |
| ) |
| ) |
| |
| const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("allowed") |
| .setPlaceholder("Edit exceptions") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Users") |
| .setDescription("Users that are unaffected by the mention filter") |
| .setValue("users"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Roles") |
| .setDescription("Roles that are unaffected by the mention filter") |
| .setValue("roles"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Channels") |
| .setDescription("Channels where anyone is unaffected by the mention filter") |
| .setValue("channels") |
| ) |
| ) |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Mention Settings") |
| .setDescription( |
| `Log when members mention:\n` + |
| `${emojiFromBoolean(true)} **${current.mass}+ members** in one message\n` + |
| `${emojiFromBoolean(current.everyone)} **Everyone**\n` + |
| `${emojiFromBoolean(current.roles)} **Roles**\n` + |
| (current.allowed.rolesToMention.length > 0 ? `> *Except for ${listToAndMore(current.allowed.rolesToMention.map(r => `<@&${r}>`), 3)}*\n` : "") + |
| "\n" + |
| `Except if...\n` + |
| `> ${current.allowed.users.length > 0 ? `Member is: ${listToAndMore(current.allowed.users.map(u => `<@${u}>`), 3)}\n` : ""}` + |
| `> ${current.allowed.roles.length > 0 ? `Member has role: ${listToAndMore(current.allowed.roles.map(r => `<@&${r}>`), 3)}\n` : ""}` + |
| `> ${current.allowed.channels.length > 0 ? `In channel: ${listToAndMore(current.allowed.channels.map(c => `<#${c}>`), 3)}\n` : ""}` |
| ) |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| |
| await interaction.editReply({embeds: [embed], components: [menu, allowedMenu, buttons]}); |
| |
| let i: ButtonInteraction | StringSelectMenuInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | StringSelectMenuInteraction; |
| } catch (e) { |
| closed = true; |
| break; |
| } |
| |
| if(i.isButton()) { |
| await i.deferUpdate(); |
| switch (i.customId) { |
| case "back": { |
| closed = true; |
| break; |
| } |
| case "everyone": { |
| current.everyone = !current.everyone; |
| break; |
| } |
| case "roles": { |
| current.roles = !current.roles; |
| break; |
| } |
| } |
| } else { |
| switch (i.customId) { |
| case "toEdit": { |
| switch (i.values[0]) { |
| case "mass": { |
| await interaction.editReply({embeds: [new EmojiEmbed() |
| .setTitle("Word Filter") |
| .setDescription("Modal opened. If you can't see it, click back and try again.") |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| ], components: [new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder() |
| .setLabel("Back") |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id")) |
| .setStyle(ButtonStyle.Primary) |
| .setCustomId("back") |
| )]}) |
| const modal = new ModalBuilder() |
| .setTitle("Mass Mention Amount") |
| .setCustomId("mass") |
| .addComponents( |
| new ActionRowBuilder<TextInputBuilder>() |
| .addComponents( |
| new TextInputBuilder() |
| .setCustomId("mass") |
| .setPlaceholder("Amount") |
| .setMinLength(1) |
| .setMaxLength(3) |
| .setStyle(TextInputStyle.Short) |
| ) |
| ) |
| await i.showModal(modal); |
| let out; |
| try { |
| out = await modalInteractionCollector( |
| m, |
| (m: Interaction) => |
| (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId, |
| (m) => m.customId === "back" |
| ); |
| } catch (e) { |
| break; |
| } |
| if (!out) break; |
| if(out.isButton()) break; |
| current.mass = parseInt(out.fields.getTextInputValue("mass")); |
| break; |
| } |
| case "roles": { |
| await i.deferUpdate(); |
| current.allowed.rolesToMention = await toSelectMenu(interaction, m, current.allowed.rolesToMention, "role", "Mention Settings"); |
| break; |
| } |
| } |
| break; |
| } |
| case "allowed": { |
| await i.deferUpdate(); |
| switch (i.values[0]) { |
| case "users": { |
| current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings"); |
| break; |
| } |
| case "roles": { |
| current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings"); |
| break; |
| } |
| case "channels": { |
| current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Mention Settings"); |
| break; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| } while(!closed); |
| return current |
| } |
| |
| const cleanMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: { |
| channels: string[], |
| allowed: { |
| roles: string[], |
| user: string[] |
| } |
| }): Promise<{ |
| channels: string[], |
| allowed: { |
| roles: string[], |
| user: string[] |
| } |
| }> => { |
| let closed = false; |
| if(!current) current = {channels: [], allowed: {roles: [], user: []}}; |
| if(!current.channels) current.channels = []; |
| if(!current.allowed) current.allowed = {roles: [], user: []}; |
| |
| const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>() |
| .addComponents( |
| new ChannelSelectMenuBuilder() |
| .setCustomId("toAdd") |
| .setPlaceholder("Select a channel") |
| ) |
| |
| const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("allowed") |
| .setPlaceholder("Edit exceptions") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Users") |
| .setDescription("Users that are unaffected by the mention filter") |
| .setValue("users"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Roles") |
| .setDescription("Roles that are unaffected by the mention filter") |
| .setValue("roles") |
| ) |
| ) |
| |
| do { |
| |
| const buttons = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Primary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id")) |
| ) |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Clean Settings") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| .setDescription( |
| `Current clean channels:\n\n` + |
| `${current.channels.length > 0 ? listToAndMore(current.channels.map(c => `<#${c}>`), 10) : "None"}\n\n` |
| ) |
| .setStatus("Success") |
| |
| |
| await interaction.editReply({embeds: [embed], components: [channelMenu, allowedMenu, buttons]}); |
| |
| let i: ButtonInteraction | ChannelSelectMenuInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | ChannelSelectMenuInteraction; |
| } catch (e) { |
| closed = true; |
| break; |
| } |
| await i.deferUpdate(); |
| if(i.isButton()) { |
| switch (i.customId) { |
| case "back": { |
| closed = true; |
| break; |
| } |
| } |
| } else { |
| switch (i.customId) { |
| case "toAdd": { |
| let channelEmbed = new EmojiEmbed() |
| .setTitle("Clean Settings") |
| .setDescription(`Editing <#${i.values[0]}>`) |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| .setStatus("Success") |
| let channelButtons = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("back") |
| .setLabel("Back") |
| .setStyle(ButtonStyle.Primary) |
| .setEmoji(getEmojiByName("CONTROL.LEFT", "id")), |
| new ButtonBuilder() |
| .setCustomId("switch") |
| .setLabel(current.channels.includes(i.values[0]!) ? "Remove" : "Add") |
| .setStyle(current.channels.includes(i.values[0]!) ? ButtonStyle.Danger : ButtonStyle.Success) |
| ) |
| |
| await i.editReply({embeds: [channelEmbed], components: [channelButtons]}); |
| let j: ButtonInteraction; |
| try { |
| j = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction; |
| } catch (e) { |
| closed = true; |
| break; |
| } |
| await j.deferUpdate(); |
| switch (j.customId) { |
| case "back": { |
| break; |
| } |
| case "switch": { |
| if(current.channels.includes(i.values[0]!)) { |
| current.channels.splice(current.channels.indexOf(i.values[0]!), 1); |
| } else { |
| current.channels.push(i.values[0]!); |
| } |
| } |
| } |
| break; |
| } |
| case "allowed": { |
| switch (i.values[0]) { |
| case "users": { |
| current.allowed.user = await toSelectMenu(interaction, m, current.allowed.user, "member", "Mention Settings"); |
| break; |
| } |
| case "roles": { |
| current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings"); |
| break; |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| } while(!closed); |
| |
| return current; |
| |
| } |
| |
| const callback = async (interaction: CommandInteraction): Promise<void> => { |
| if (!interaction.guild) return; |
| const m = await interaction.reply({embeds: LoadingEmbed, fetchReply: true, ephemeral: true}); |
| const config = (await client.database.guilds.read(interaction.guild.id)).filters; |
| |
| let closed = false; |
| |
| const button = new ActionRowBuilder<ButtonBuilder>() |
| .addComponents( |
| new ButtonBuilder() |
| .setCustomId("save") |
| .setLabel("Save") |
| .setStyle(ButtonStyle.Success) |
| ) |
| |
| do { |
| |
| const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>() |
| .addComponents( |
| new StringSelectMenuBuilder() |
| .setCustomId("filter") |
| .setPlaceholder("Select a filter to edit") |
| .addOptions( |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Invites") |
| .setDescription("Automatically delete messages containing server invites") |
| .setValue("invites"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Mentions") |
| .setDescription("Deletes messages with excessive mentions") |
| .setValue("mentions"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Words") |
| .setDescription("Delete messages containing filtered words") |
| .setValue("words"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Malware") |
| .setDescription("Automatically delete files and links containing malware") |
| .setValue("malware"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Images") |
| .setDescription("Checks performed on images (NSFW, size checking, etc.)") |
| .setValue("images"), |
| new StringSelectMenuOptionBuilder() |
| .setLabel("Clean") |
| .setDescription("Automatically delete new messages in specific channels") |
| .setValue("clean") |
| ) |
| ); |
| |
| const embed = new EmojiEmbed() |
| .setTitle("Automod Settings") |
| .setDescription( |
| `${emojiFromBoolean(config.invite.enabled)} **Invites**\n` + |
| `${emojiFromBoolean(config.pings.everyone || config.pings.mass > 0 || config.pings.roles)} **Mentions**\n` + |
| `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` + |
| `${emojiFromBoolean(config.malware)} **Malware**\n` + |
| `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**\n` + |
| `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n` |
| ) |
| .setStatus("Success") |
| .setEmoji("GUILD.SETTINGS.GREEN") |
| |
| |
| await interaction.editReply({embeds: [embed], components: [selectMenu, button]}); |
| |
| let i: StringSelectMenuInteraction | ButtonInteraction; |
| try { |
| i = await m.awaitMessageComponent({filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id, time: 300000}) as StringSelectMenuInteraction | ButtonInteraction; |
| } catch (e) { |
| closed = true; |
| continue; |
| } |
| await i.deferUpdate(); |
| if(i.isButton()) { |
| await client.database.guilds.write(interaction.guild.id, {filters: config}); |
| } else { |
| switch(i.values[0]) { |
| case "invites": { |
| config.invite = await inviteMenu(i, m, config.invite); |
| break; |
| } |
| case "mentions": { |
| config.pings = await mentionMenu(i, m, config.pings); |
| break; |
| } |
| case "words": { |
| config.wordFilter = await wordMenu(i, m, config.wordFilter); |
| break; |
| } |
| case "malware": { |
| config.malware = !config.malware; |
| break; |
| } |
| case "images": { |
| const next = await imageMenu(i, m, config.images); |
| config.images = next; |
| break; |
| } |
| case "clean": { |
| const next = await cleanMenu(i, m, config.clean); |
| config.clean = next; |
| break; |
| } |
| } |
| } |
| |
| } while(!closed) |
| |
| }; |
| |
| const check = (interaction: CommandInteraction, _partial: boolean = false) => { |
| const member = interaction.member as Discord.GuildMember; |
| if (!member.permissions.has("ManageMessages")) |
| return "You must have the *Manage Messages* permission to use this command"; |
| return true; |
| }; |
| |
| export { command }; |
| export { callback }; |
| export { check }; |