blob: b9f2453d6df38bd7269266260e9f32336e3a756e [file] [log] [blame]
TheCodedProf8b3da212023-02-02 15:09:55 -05001import type Discord from "discord.js";
2import { ActionRowBuilder, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, CommandInteraction, Message, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder } from "discord.js";
3import type { SlashCommandSubcommandBuilder } from "discord.js";
4import { LoadingEmbed } from "../../utils/defaults.js";
5import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
6import client from "../../utils/client.js";
7import getEmojiByName from "../../utils/getEmojiByName.js";
8
9const command = (builder: SlashCommandSubcommandBuilder) =>
10 builder.setName("automod").setDescription("Setting for automatic moderation features");
11
12
13const emojiFromBoolean = (bool: boolean, id?: string) => bool ? getEmojiByName("CONTROL.TICK", id) : getEmojiByName("CONTROL.CROSS", id);
14
15
16const imageMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: {
17 NSFW: boolean,
18 size: boolean
19}): Promise<{NSFW: boolean, size: boolean}> => {
20 let closed = false;
21 do {
22 const options = new ActionRowBuilder<ButtonBuilder>()
23 .addComponents(
24 new ButtonBuilder()
25 .setCustomId("back")
26 .setLabel("Back")
27 .setStyle(ButtonStyle.Secondary)
28 .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
29 new ButtonBuilder()
30 .setCustomId("nsfw")
31 .setLabel("NSFW")
32 .setStyle(current.NSFW ? ButtonStyle.Success : ButtonStyle.Danger)
33 .setEmoji(emojiFromBoolean(current.NSFW, "id") as APIMessageComponentEmoji),
34 new ButtonBuilder()
35 .setCustomId("size")
36 .setLabel("Size")
37 .setStyle(current.size ? ButtonStyle.Success : ButtonStyle.Danger)
38 .setEmoji(emojiFromBoolean(current.size, "id") as APIMessageComponentEmoji)
39 )
40
41 const embed = new EmojiEmbed()
42 .setTitle("Image Settings")
43 .setDescription(
44 `${emojiFromBoolean(current.NSFW)} **NSFW**\n` +
45 `${emojiFromBoolean(current.size)} **Size**\n`
46 )
47
48 await interaction.editReply({embeds: [embed], components: [options]});
49
50 let i: ButtonInteraction;
51 try {
52 i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction;
53 } catch (e) {
54 return current;
55 }
56 await i.deferUpdate();
57 switch(i.customId) {
58 case "back":
59 closed = true;
60 break;
61 case "nsfw":
62 current.NSFW = !current.NSFW;
63 break;
64 case "size":
65 current.size = !current.size;
66 break;
67 }
68 } while(!closed);
69 return current;
70}
71
72const wordMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: {
73 enabled: boolean,
74 words: {strict: string[], loose: string[]},
75 allowed: {user: string[], roles: string[], channels: string[]}
76}): Promise<{
77 enabled: boolean,
78 words: {strict: string[], loose: string[]},
79 allowed: {user: string[], roles: string[], channels: string[]}
80}> => {
81
82}
83
84const inviteMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: {
85 enabled: boolean,
86 allowed: {user: string[], roles: string[], channels: string[]}
87}): Promise<{
88 enabled: boolean,
89 allowed: {user: string[], roles: string[], channels: string[]}
90}> => {
91
92}
93
94const mentionMenu = async (interaction: StringSelectMenuInteraction, m: Message, current: {
95 mass: number,
96 everyone: boolean,
97 roles: boolean,
98 allowed: {
99 roles: string[],
100 rolesToMention: string[],
101 users: string[],
102 channels: string[]
103 }
104}): Promise<{
105 mass: number,
106 everyone: boolean,
107 roles: boolean,
108 allowed: {
109 roles: string[],
110 rolesToMention: string[],
111 users: string[],
112 channels: string[]
113 }
114}> => {
115
116}
117
118const callback = async (interaction: CommandInteraction): Promise<void> => {
119 if (!interaction.guild) return;
120 const m = await interaction.reply({embeds: LoadingEmbed, fetchReply: true, ephemeral: true});
121 const config = (await client.database.guilds.read(interaction.guild.id)).filters;
122
123 let closed = false;
124
125 const button = new ActionRowBuilder<ButtonBuilder>()
126 .addComponents(
127 new ButtonBuilder()
128 .setCustomId("save")
129 .setLabel("Save")
130 .setStyle(ButtonStyle.Success)
131 )
132
133 do {
134
135 const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
136 .addComponents(
137 new StringSelectMenuBuilder()
138 .setCustomId("filter")
139 .setPlaceholder("Select a filter to edit")
140 .addOptions(
141 new StringSelectMenuOptionBuilder()
142 .setLabel("Invites")
143 .setDescription("Automatically delete messages containing server invites")
144 .setValue("invites"),
145 new StringSelectMenuOptionBuilder()
146 .setLabel("Mentions")
147 .setDescription("Deletes messages with excessive mentions")
148 .setValue("mentions"),
149 new StringSelectMenuOptionBuilder()
150 .setLabel("Words")
151 .setDescription("Delete messages containing filtered words")
152 .setValue("words"),
153 new StringSelectMenuOptionBuilder()
154 .setLabel("Malware")
155 .setDescription("Automatically delete files and links containing malware")
156 .setValue("malware"),
157 new StringSelectMenuOptionBuilder()
158 .setLabel("Images")
159 .setDescription("Checks performed on images (NSFW, size checking, etc.)")
160 .setValue("images")
161 )
162 );
163
164 const embed = new EmojiEmbed()
165 .setTitle("Automod Settings")
166 .setDescription(
167 `${emojiFromBoolean(config.invite.enabled)} **Invites**}\n` +
168 `${emojiFromBoolean(config.pings.everyone || config.pings.mass > 0 || config.pings.roles)} **Mentions**\n` +
169 `${emojiFromBoolean(config.wordFilter.enabled)} **Words**\n` +
170 `${emojiFromBoolean(config.malware)} **Malware**\n` +
171 `${emojiFromBoolean(config.images.NSFW || config.images.size)} **Images**}\n`
172 )
173
174
175 await interaction.editReply({embeds: [embed], components: [selectMenu, button]});
176
177 let i: StringSelectMenuInteraction | ButtonInteraction;
178 try {
179 i = await m.awaitMessageComponent({filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id, time: 300000}) as StringSelectMenuInteraction | ButtonInteraction;
180 } catch (e) {
181 closed = true;
182 return;
183 }
184 if(!i) return;
185 if(i.isButton()) {
186 await i.deferUpdate();
187 await client.database.guilds.write(interaction.guild.id, {filters: config});
188 } else {
189 switch(i.values[0]) {
190 case "invites":
191 break;
192 case "mentions":
193 break;
194 case "words":
195 break;
196 case "malware":
197 await i.deferUpdate();
198 config.malware = !config.malware;
199 break;
200 case "images":
201 let next = await imageMenu(i, m, config.images);
202 if(next) config.images = next;
203 break;
204 }
205 }
206
207 } while(!closed)
208
209};
210
211const check = (interaction: CommandInteraction, _partial: boolean = false) => {
212 const member = interaction.member as Discord.GuildMember;
213 if (!member.permissions.has("ManageMessages"))
214 return "You must have the *Manage Messages* permission to use this command";
215 return true;
216};
217
218export { command };
219export { callback };
220export { check };