mirror of https://github.com/clickscodes/nucleus
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.
936 lines
41 KiB
936 lines
41 KiB
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 };
|