blob: 4e7703c21465dd4b0177e164b58a0573fac8ed7d [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import { LoadingEmbed } from "./../utils/defaultEmbeds.js";
pineafan3a02ea32022-08-11 21:35:04 +01002import Discord, {
3 MessageActionRow,
4 MessageButton,
5 MessageComponentInteraction,
6 MessageSelectOptionData,
7 Guild,
8 CommandInteraction,
9 GuildTextBasedChannel,
10 Message,
11 SelectMenuInteraction
12} from "discord.js";
pineafan813bdf42022-07-24 10:39:10 +010013import EmojiEmbed from "../utils/generateEmojiEmbed.js";
14import getEmojiByName from "../utils/getEmojiByName.js";
15import createPageIndicator from "../utils/createPageIndicator.js";
pineafan813bdf42022-07-24 10:39:10 +010016
17class Embed {
18 embed: Discord.MessageEmbed;
19 title: string;
pineafan63fc5e22022-08-04 22:04:10 +010020 description = "";
21 pageId = 0;
pineafan3a02ea32022-08-11 21:35:04 +010022
23 constructor() {
24 this.embed = new Discord.MessageEmbed();
25 this.title = "";
26 }
Skyler Grey75ea9172022-08-06 10:22:23 +010027 setEmbed(embed: Discord.MessageEmbed) {
28 this.embed = embed;
29 return this;
30 }
31 setTitle(title: string) {
32 this.title = title;
33 return this;
34 }
35 setDescription(description: string) {
36 this.description = description;
37 return this;
38 }
39 setPageId(pageId: number) {
40 this.pageId = pageId;
41 return this;
42 }
pineafan813bdf42022-07-24 10:39:10 +010043}
44
pineafan3a02ea32022-08-11 21:35:04 +010045export default async (guild: Guild, interaction?: CommandInteraction) => {
46 let c: GuildTextBasedChannel | null = guild.publicUpdatesChannel ? guild.publicUpdatesChannel : guild.systemChannel;
Skyler Grey75ea9172022-08-06 10:22:23 +010047 c = c
48 ? c
pineafan3a02ea32022-08-11 21:35:04 +010049 : (guild.channels.cache.find(
Skyler Grey75ea9172022-08-06 10:22:23 +010050 (ch) =>
pineafan3a02ea32022-08-11 21:35:04 +010051 [
52 "GUILD_TEXT",
53 "GUILD_NEWS",
54 "GUILD_NEWS_THREAD",
55 "GUILD_PRIVATE_THREAD",
56 "GUILD_PUBLIC_THREAD"
57 ].includes(ch.type) &&
Skyler Grey11236ba2022-08-08 21:13:33 +010058 ch.permissionsFor(guild.roles.everyone).has("SEND_MESSAGES") &&
pineafan3a02ea32022-08-11 21:35:04 +010059 ch.permissionsFor(guild.me!).has("EMBED_LINKS")
60 ) as GuildTextBasedChannel | undefined) ?? null;
61 if (interaction) c = interaction.channel as GuildTextBasedChannel;
62 if (!c) {
63 return;
64 }
pineafan63fc5e22022-08-04 22:04:10 +010065 const pages = [
pineafan813bdf42022-07-24 10:39:10 +010066 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010067 .setEmbed(
68 new EmojiEmbed()
69 .setTitle("Welcome to Nucleus")
70 .setDescription(
71 "Thanks for adding Nucleus to your server\n\n" +
72 "On the next few pages you can find instructions on getting started, and commands you may want to set up\n\n" +
73 "If you need support, have questions or want features, you can let us know in [Clicks](https://discord.gg/bPaNnxe)"
74 )
75 .setEmoji("NUCLEUS.LOGO")
76 .setStatus("Danger")
77 )
78 .setTitle("Welcome")
79 .setDescription("About Nucleus")
80 .setPageId(0),
pineafan813bdf42022-07-24 10:39:10 +010081 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010082 .setEmbed(
83 new EmojiEmbed()
84 .setTitle("Logging")
85 .setDescription(
86 "Nucleus can log server events and keep you informed with what content is being posted to your server.\n" +
87 "We have 2 different types of logs, which each can be configured to send to a channel of your choice:\n" +
88 "**General Logs:** These are events like kicks and channel changes etc.\n" +
89 "**Warning Logs:** Warnings like NSFW avatars and spam etc. that may require action by a server staff member. " +
90 "These go to to a separate staff notifications channel.\n\n" +
91 "A general log channel can be set with `/settings log`\n" +
92 "A warning log channel can be set with `/settings warnings channel`"
93 )
94 .setEmoji("ICONS.LOGGING")
95 .setStatus("Danger")
96 )
97 .setTitle("Logging")
98 .setDescription("Logging, staff warning logs etc.")
99 .setPageId(1),
pineafan813bdf42022-07-24 10:39:10 +0100100 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100101 .setEmbed(
102 new EmojiEmbed()
103 .setTitle("Moderation")
104 .setDescription(
105 "Nucleus has a number of commands that can be used to moderate your server.\n" +
106 "These commands are all found under `/mod`, and they include:\n" +
107 `**${getEmojiByName(
108 "PUNISH.WARN.YELLOW"
109 )} Warn:** The user is warned (via DM) that they violated server rules.\n` +
110 `**${getEmojiByName(
111 "PUNISH.CLEARHISTORY"
112 )} Clear:** Some messages from a user are deleted in a channel.\n` +
113 `**${getEmojiByName(
114 "PUNISH.MUTE.YELLOW"
115 )} Mute:** The user is unable to send messages or join voice chats.\n` +
116 `**${getEmojiByName(
117 "PUNISH.MUTE.GREEN"
118 )} Unmute:** The user is able to send messages in the server.\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100119 `**${getEmojiByName("PUNISH.KICK.RED")} Kick:** The user is removed from the server.\n` +
Skyler Grey75ea9172022-08-06 10:22:23 +0100120 `**${getEmojiByName(
121 "PUNISH.SOFTBAN"
122 )} Softban:** Kicks the user, deleting their messages from every channel.\n` +
123 `**${getEmojiByName(
124 "PUNISH.BAN.RED"
125 )} Ban:** The user is removed from the server, and they are unable to rejoin.\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100126 `**${getEmojiByName("PUNISH.BAN.GREEN")} Unban:** The user is able to rejoin the server.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100127 )
128 .setEmoji("PUNISH.BAN.RED")
129 .setStatus("Danger")
130 )
131 .setTitle("Moderation")
132 .setDescription("Basic moderation commands")
133 .setPageId(2),
pineafan813bdf42022-07-24 10:39:10 +0100134 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100135 .setEmbed(
136 new EmojiEmbed()
137 .setTitle("Verify")
138 .setDescription(
139 "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
140 "This is done by running `/verify` which sends a message only the user can see, giving them a link to a CAPTCHA to verify.\n" +
141 "After the user complete's the CAPTCHA, they are given a role and can use the permissions accordingly.\n" +
142 "You can set the role given with `/settings verify`"
143 )
144 .setEmoji("CONTROL.REDTICK")
145 .setStatus("Danger")
146 )
147 .setTitle("Verify")
148 .setDescription("Captcha verification system")
149 .setPageId(3),
pineafan813bdf42022-07-24 10:39:10 +0100150 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100151 .setEmbed(
152 new EmojiEmbed()
153 .setTitle("Content Scanning")
154 .setDescription(
155 "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
156 "Nucleus can detect, delete, and punish users for sending NSFW content, or links to scam or adult sites.\n" +
157 "You can set the threshold for this in `/settings automation`" // TODO
158 )
159 .setEmoji("MOD.IMAGES.TOOSMALL")
160 .setStatus("Danger")
161 )
162 .setTitle("Content Scanning")
163 .setDescription("Content (NSFW, malware, scams) scanning")
164 .setPageId(4),
pineafan813bdf42022-07-24 10:39:10 +0100165 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100166 .setEmbed(
167 new EmojiEmbed()
168 .setTitle("Tickets")
169 .setDescription(
170 "Nucleus has a ticket system that allows users to create tickets and have a support team respond to them.\n" +
171 "Tickets can be created with `/ticket create` and a channel is created, pinging the user and support role.\n" +
172 "When the ticket is resolved, anyone can run `/ticket close` (or click the button) to close it.\n" +
173 "Running `/ticket close` again will delete the ticket."
174 )
175 .setEmoji("GUILD.TICKET.CLOSE")
176 .setStatus("Danger")
177 )
178 .setTitle("Tickets")
179 .setDescription("Ticket system")
180 .setPageId(5),
pineafan813bdf42022-07-24 10:39:10 +0100181 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100182 .setEmbed(
183 new EmojiEmbed()
184 .setTitle("Tags")
185 .setDescription(
186 "Add a tag system to your server with the `/tag` and `/tags` commands.\n" +
187 "To create a tag, type `/tags create <tag name> <tag content>`.\n" +
188 "Tag names and content can be edited with `/tags edit`.\n" +
189 "To delete a tag, type `/tags delete <tag name>`.\n" +
190 "To view all tags, type `/tags list`.\n"
191 )
192 .setEmoji("PUNISH.NICKNAME.RED")
193 .setStatus("Danger")
194 )
195 .setTitle("Tags")
196 .setDescription("Tag system")
197 .setPageId(6),
pineafan813bdf42022-07-24 10:39:10 +0100198 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100199 .setEmbed(
200 new EmojiEmbed()
201 .setTitle("Premium")
202 .setDescription(
203 "In the near future, we will be releasing extra premium only features.\n" +
204 "These features will include:\n\n" +
205 "**Attachment logs**\n> When a message with attachments is edited or deleted, the logs will also include the images sent.\n" +
206 "\nPremium is not yet available. Check `/nucleus premium` for updates on features and pricing"
207 )
208 .setEmoji("NUCLEUS.COMMANDS.LOCK")
209 .setStatus("Danger")
210 )
211 .setTitle("Premium")
212 .setDescription("Premium features")
213 .setPageId(7)
pineafan63fc5e22022-08-04 22:04:10 +0100214 ];
pineafan3a02ea32022-08-11 21:35:04 +0100215 let m: Message;
Skyler Grey75ea9172022-08-06 10:22:23 +0100216 if (interaction) {
pineafan3a02ea32022-08-11 21:35:04 +0100217 m = (await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100218 embeds: LoadingEmbed,
219 fetchReply: true,
220 ephemeral: true
pineafan3a02ea32022-08-11 21:35:04 +0100221 })) as Message;
Skyler Grey75ea9172022-08-06 10:22:23 +0100222 } else {
223 m = await c.send({ embeds: LoadingEmbed });
224 }
pineafan813bdf42022-07-24 10:39:10 +0100225 let page = 0;
226
pineafan3a02ea32022-08-11 21:35:04 +0100227 const f = async (component: MessageComponentInteraction) => {
Skyler Grey11236ba2022-08-08 21:13:33 +0100228 return (component.member as Discord.GuildMember).permissions.has("MANAGE_GUILD");
pineafan63fc5e22022-08-04 22:04:10 +0100229 };
pineafan813bdf42022-07-24 10:39:10 +0100230
231 let selectPaneOpen = false;
232
Skyler Greyf21323a2022-08-13 23:58:22 +0100233 let cancelled = false;
234 let timedOut = false;
235 while (!cancelled && !timedOut) {
pineafan3a02ea32022-08-11 21:35:04 +0100236 let selectPane: MessageActionRow[] = [];
pineafan813bdf42022-07-24 10:39:10 +0100237
238 if (selectPaneOpen) {
pineafan3a02ea32022-08-11 21:35:04 +0100239 const options: MessageSelectOptionData[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100240 pages.forEach((embed) => {
pineafan3a02ea32022-08-11 21:35:04 +0100241 options.push({
242 label: embed.title,
243 value: embed.pageId.toString(),
244 description: embed.description || ""
245 });
pineafan63fc5e22022-08-04 22:04:10 +0100246 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100247 selectPane = [
248 new MessageActionRow().addComponents([
249 new Discord.MessageSelectMenu()
250 .addOptions(options)
251 .setCustomId("page")
252 .setMaxValues(1)
253 .setPlaceholder("Choose a page...")
254 ])
255 ];
pineafan813bdf42022-07-24 10:39:10 +0100256 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100257 const components = selectPane.concat([
258 new MessageActionRow().addComponents([
259 new MessageButton()
260 .setCustomId("left")
261 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
262 .setStyle("SECONDARY")
263 .setDisabled(page === 0),
264 new MessageButton()
265 .setCustomId("select")
266 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
267 .setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY")
268 .setDisabled(false),
269 new MessageButton()
270 .setCustomId("right")
271 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
272 .setStyle("SECONDARY")
273 .setDisabled(page === pages.length - 1)
274 ])
275 ]);
pineafan813bdf42022-07-24 10:39:10 +0100276 if (interaction) {
pineafan3a02ea32022-08-11 21:35:04 +0100277 const em = new Discord.MessageEmbed(pages[page]!.embed);
Skyler Grey11236ba2022-08-08 21:13:33 +0100278 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan813bdf42022-07-24 10:39:10 +0100279 await interaction.editReply({
280 embeds: [em],
281 components: components
282 });
283 } else {
pineafan3a02ea32022-08-11 21:35:04 +0100284 const em = new Discord.MessageEmbed(pages[page]!.embed);
Skyler Grey11236ba2022-08-08 21:13:33 +0100285 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan3a02ea32022-08-11 21:35:04 +0100286 (await m.edit({
pineafan813bdf42022-07-24 10:39:10 +0100287 embeds: [em],
pineafan3a02ea32022-08-11 21:35:04 +0100288 components: components
289 })) as Message;
pineafan813bdf42022-07-24 10:39:10 +0100290 }
pineafan63fc5e22022-08-04 22:04:10 +0100291 let i;
pineafan813bdf42022-07-24 10:39:10 +0100292 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100293 i = await m.awaitMessageComponent({
294 filter: interaction
295 ? () => {
296 return true;
297 }
298 : f,
299 time: 300000
300 });
301 } catch (e) {
Skyler Greyf21323a2022-08-13 23:58:22 +0100302 timedOut = true;
303 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100304 }
pineafan63fc5e22022-08-04 22:04:10 +0100305 i.deferUpdate();
pineafan3a02ea32022-08-11 21:35:04 +0100306 if (!("customId" in i.component)) {
307 continue;
308 } else if (i.component.customId === "left") {
pineafan813bdf42022-07-24 10:39:10 +0100309 if (page > 0) page--;
310 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100311 } else if (i.component.customId === "right") {
pineafan813bdf42022-07-24 10:39:10 +0100312 if (page < pages.length - 1) page++;
313 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100314 } else if (i.component.customId === "select") {
pineafan813bdf42022-07-24 10:39:10 +0100315 selectPaneOpen = !selectPaneOpen;
pineafane23c4ec2022-07-27 21:56:27 +0100316 } else if (i.component.customId === "page") {
pineafan3a02ea32022-08-11 21:35:04 +0100317 page = parseInt((i as SelectMenuInteraction).values[0]!);
pineafan813bdf42022-07-24 10:39:10 +0100318 selectPaneOpen = false;
319 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100320 cancelled = true;
pineafan813bdf42022-07-24 10:39:10 +0100321 }
322 }
Skyler Greyf21323a2022-08-13 23:58:22 +0100323 if (timedOut) {
324 if (interaction) {
325 const em = new Discord.MessageEmbed(pages[page]!.embed);
326 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
327 text: "Message timed out"
328 });
329 await interaction.editReply({
330 embeds: [em],
331 components: []
332 });
333 } else {
334 const em = new Discord.MessageEmbed(pages[page]!.embed);
335 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
336 text: "Message timed out"
337 });
338 await m.edit({
339 embeds: [em],
340 components: []
341 });
342 }
pineafan813bdf42022-07-24 10:39:10 +0100343 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100344 if (interaction) {
345 const em = new Discord.MessageEmbed(pages[page]!.embed);
346 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
347 em.setFooter({ text: "Message closed" });
348 interaction.editReply({
349 embeds: [em],
350 components: []
351 });
352 } else {
353 m.delete();
354 }
pineafan813bdf42022-07-24 10:39:10 +0100355 }
pineafan63fc5e22022-08-04 22:04:10 +0100356};