You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Nucleus/src/commands/settings/automod.ts

936 lines
41 KiB

import type Discord from "discord.js";
3 years ago
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";
3 years ago
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 {
3 years ago
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 {
3 years ago
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": {
3 years ago
closed = true;
break;
}
case "enabled": {
3 years ago
current.enabled = !current.enabled;
break;
}
3 years ago
}
} else {
switch(i.values[0]) {
case "words": {
3 years ago
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(", "))
3 years ago
.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(", "))
3 years ago
.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": {
3 years ago
await i.deferUpdate();
current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Word Filter");
break;
}
case "allowedRoles": {
3 years ago
await i.deferUpdate();
current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Word Filter");
break;
}
case "allowedChannels": {
3 years ago
await i.deferUpdate();
current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Word Filter");
break;
}
3 years ago
}
}
} 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` +
3 years ago
`**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")
3 years ago
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 {
3 years ago
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": {
3 years ago
closed = true;
break;
}
case "everyone": {
3 years ago
current.everyone = !current.everyone;
break;
}
case "roles": {
3 years ago
current.roles = !current.roles;
break;
}
3 years ago
}
} else {
switch (i.customId) {
case "toEdit": {
3 years ago
switch (i.values[0]) {
case "mass": {
3 years ago
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": {
3 years ago
await i.deferUpdate();
current.allowed.rolesToMention = await toSelectMenu(interaction, m, current.allowed.rolesToMention, "role", "Mention Settings");
break;
}
3 years ago
}
break;
}
case "allowed": {
3 years ago
await i.deferUpdate();
switch (i.values[0]) {
case "users": {
3 years ago
current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings");
break;
}
case "roles": {
3 years ago
current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings");
break;
}
case "channels": {
3 years ago
current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Mention Settings");
break;
}
3 years ago
}
break;
}
3 years ago
}
}
} 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 };