blob: 6829ef2091b953bb9f169d0a904c9948d5e96551 [file] [log] [blame]
PineaFan0d06edc2023-01-17 22:10:31 +00001import { LoadingEmbed } from "../utils/defaults.js";
pineafan3a02ea32022-08-11 21:35:04 +01002import Discord, {
TheCodedProf21c08592022-09-13 14:14:43 -04003 ActionRowBuilder,
4 ButtonBuilder,
pineafan3a02ea32022-08-11 21:35:04 +01005 MessageComponentInteraction,
PineaFane6ba7882023-01-18 20:41:16 +00006 StringSelectMenuInteraction,
pineafan3a02ea32022-08-11 21:35:04 +01007 Guild,
8 CommandInteraction,
9 GuildTextBasedChannel,
10 Message,
PineaFane6ba7882023-01-18 20:41:16 +000011 ButtonStyle,
12 ChannelType
pineafan3a02ea32022-08-11 21:35:04 +010013} from "discord.js";
pineafan813bdf42022-07-24 10:39:10 +010014import EmojiEmbed from "../utils/generateEmojiEmbed.js";
15import getEmojiByName from "../utils/getEmojiByName.js";
16import createPageIndicator from "../utils/createPageIndicator.js";
PineaFane6ba7882023-01-18 20:41:16 +000017import { Embed } from "../utils/defaults.js";
pineafan813bdf42022-07-24 10:39:10 +010018
pineafan3a02ea32022-08-11 21:35:04 +010019export default async (guild: Guild, interaction?: CommandInteraction) => {
20 let c: GuildTextBasedChannel | null = guild.publicUpdatesChannel ? guild.publicUpdatesChannel : guild.systemChannel;
Skyler Grey75ea9172022-08-06 10:22:23 +010021 c = c
22 ? c
pineafan3a02ea32022-08-11 21:35:04 +010023 : (guild.channels.cache.find(
Skyler Grey75ea9172022-08-06 10:22:23 +010024 (ch) =>
pineafan3a02ea32022-08-11 21:35:04 +010025 [
PineaFane6ba7882023-01-18 20:41:16 +000026 ChannelType.GuildText,
27 ChannelType.GuildAnnouncement,
28 ChannelType.PublicThread,
29 ChannelType.PrivateThread,
30 ChannelType.AnnouncementThread
pineafan3a02ea32022-08-11 21:35:04 +010031 ].includes(ch.type) &&
PineaFane6ba7882023-01-18 20:41:16 +000032 ch.permissionsFor(guild.roles.everyone).has("SendMessages") &&
33 ch.permissionsFor(guild.members.me!).has("EmbedLinks")
pineafan3a02ea32022-08-11 21:35:04 +010034 ) as GuildTextBasedChannel | undefined) ?? null;
35 if (interaction) c = interaction.channel as GuildTextBasedChannel;
36 if (!c) {
37 return;
38 }
pineafan63fc5e22022-08-04 22:04:10 +010039 const pages = [
pineafan813bdf42022-07-24 10:39:10 +010040 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010041 .setEmbed(
42 new EmojiEmbed()
43 .setTitle("Welcome to Nucleus")
44 .setDescription(
45 "Thanks for adding Nucleus to your server\n\n" +
46 "On the next few pages you can find instructions on getting started, and commands you may want to set up\n\n" +
47 "If you need support, have questions or want features, you can let us know in [Clicks](https://discord.gg/bPaNnxe)"
48 )
49 .setEmoji("NUCLEUS.LOGO")
50 .setStatus("Danger")
51 )
52 .setTitle("Welcome")
53 .setDescription("About Nucleus")
54 .setPageId(0),
pineafan813bdf42022-07-24 10:39:10 +010055 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010056 .setEmbed(
57 new EmojiEmbed()
58 .setTitle("Logging")
59 .setDescription(
60 "Nucleus can log server events and keep you informed with what content is being posted to your server.\n" +
61 "We have 2 different types of logs, which each can be configured to send to a channel of your choice:\n" +
62 "**General Logs:** These are events like kicks and channel changes etc.\n" +
63 "**Warning Logs:** Warnings like NSFW avatars and spam etc. that may require action by a server staff member. " +
64 "These go to to a separate staff notifications channel.\n\n" +
65 "A general log channel can be set with `/settings log`\n" +
66 "A warning log channel can be set with `/settings warnings channel`"
67 )
68 .setEmoji("ICONS.LOGGING")
69 .setStatus("Danger")
70 )
71 .setTitle("Logging")
72 .setDescription("Logging, staff warning logs etc.")
73 .setPageId(1),
pineafan813bdf42022-07-24 10:39:10 +010074 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010075 .setEmbed(
76 new EmojiEmbed()
77 .setTitle("Moderation")
78 .setDescription(
79 "Nucleus has a number of commands that can be used to moderate your server.\n" +
80 "These commands are all found under `/mod`, and they include:\n" +
81 `**${getEmojiByName(
82 "PUNISH.WARN.YELLOW"
83 )} Warn:** The user is warned (via DM) that they violated server rules.\n` +
84 `**${getEmojiByName(
85 "PUNISH.CLEARHISTORY"
86 )} Clear:** Some messages from a user are deleted in a channel.\n` +
87 `**${getEmojiByName(
88 "PUNISH.MUTE.YELLOW"
89 )} Mute:** The user is unable to send messages or join voice chats.\n` +
90 `**${getEmojiByName(
91 "PUNISH.MUTE.GREEN"
92 )} Unmute:** The user is able to send messages in the server.\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +010093 `**${getEmojiByName("PUNISH.KICK.RED")} Kick:** The user is removed from the server.\n` +
Skyler Grey75ea9172022-08-06 10:22:23 +010094 `**${getEmojiByName(
95 "PUNISH.SOFTBAN"
96 )} Softban:** Kicks the user, deleting their messages from every channel.\n` +
97 `**${getEmojiByName(
98 "PUNISH.BAN.RED"
99 )} Ban:** The user is removed from the server, and they are unable to rejoin.\n` +
Skyler Grey11236ba2022-08-08 21:13:33 +0100100 `**${getEmojiByName("PUNISH.BAN.GREEN")} Unban:** The user is able to rejoin the server.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100101 )
102 .setEmoji("PUNISH.BAN.RED")
103 .setStatus("Danger")
104 )
105 .setTitle("Moderation")
106 .setDescription("Basic moderation commands")
107 .setPageId(2),
pineafan813bdf42022-07-24 10:39:10 +0100108 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100109 .setEmbed(
110 new EmojiEmbed()
111 .setTitle("Verify")
112 .setDescription(
113 "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
114 "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" +
115 "After the user complete's the CAPTCHA, they are given a role and can use the permissions accordingly.\n" +
116 "You can set the role given with `/settings verify`"
117 )
118 .setEmoji("CONTROL.REDTICK")
119 .setStatus("Danger")
120 )
121 .setTitle("Verify")
122 .setDescription("Captcha verification system")
123 .setPageId(3),
pineafan813bdf42022-07-24 10:39:10 +0100124 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100125 .setEmbed(
126 new EmojiEmbed()
127 .setTitle("Content Scanning")
128 .setDescription(
129 "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
130 "Nucleus can detect, delete, and punish users for sending NSFW content, or links to scam or adult sites.\n" +
131 "You can set the threshold for this in `/settings automation`" // TODO
132 )
133 .setEmoji("MOD.IMAGES.TOOSMALL")
134 .setStatus("Danger")
135 )
136 .setTitle("Content Scanning")
137 .setDescription("Content (NSFW, malware, scams) scanning")
138 .setPageId(4),
pineafan813bdf42022-07-24 10:39:10 +0100139 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100140 .setEmbed(
141 new EmojiEmbed()
142 .setTitle("Tickets")
143 .setDescription(
144 "Nucleus has a ticket system that allows users to create tickets and have a support team respond to them.\n" +
145 "Tickets can be created with `/ticket create` and a channel is created, pinging the user and support role.\n" +
146 "When the ticket is resolved, anyone can run `/ticket close` (or click the button) to close it.\n" +
147 "Running `/ticket close` again will delete the ticket."
148 )
149 .setEmoji("GUILD.TICKET.CLOSE")
150 .setStatus("Danger")
151 )
152 .setTitle("Tickets")
153 .setDescription("Ticket system")
154 .setPageId(5),
pineafan813bdf42022-07-24 10:39:10 +0100155 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100156 .setEmbed(
157 new EmojiEmbed()
158 .setTitle("Tags")
159 .setDescription(
160 "Add a tag system to your server with the `/tag` and `/tags` commands.\n" +
161 "To create a tag, type `/tags create <tag name> <tag content>`.\n" +
162 "Tag names and content can be edited with `/tags edit`.\n" +
163 "To delete a tag, type `/tags delete <tag name>`.\n" +
164 "To view all tags, type `/tags list`.\n"
165 )
166 .setEmoji("PUNISH.NICKNAME.RED")
167 .setStatus("Danger")
168 )
169 .setTitle("Tags")
170 .setDescription("Tag system")
171 .setPageId(6),
pineafan813bdf42022-07-24 10:39:10 +0100172 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100173 .setEmbed(
174 new EmojiEmbed()
175 .setTitle("Premium")
176 .setDescription(
177 "In the near future, we will be releasing extra premium only features.\n" +
178 "These features will include:\n\n" +
179 "**Attachment logs**\n> When a message with attachments is edited or deleted, the logs will also include the images sent.\n" +
180 "\nPremium is not yet available. Check `/nucleus premium` for updates on features and pricing"
181 )
182 .setEmoji("NUCLEUS.COMMANDS.LOCK")
183 .setStatus("Danger")
184 )
185 .setTitle("Premium")
186 .setDescription("Premium features")
187 .setPageId(7)
pineafan63fc5e22022-08-04 22:04:10 +0100188 ];
pineafan3a02ea32022-08-11 21:35:04 +0100189 let m: Message;
Skyler Grey75ea9172022-08-06 10:22:23 +0100190 if (interaction) {
pineafan3a02ea32022-08-11 21:35:04 +0100191 m = (await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100192 embeds: LoadingEmbed,
193 fetchReply: true,
194 ephemeral: true
pineafan3a02ea32022-08-11 21:35:04 +0100195 })) as Message;
Skyler Grey75ea9172022-08-06 10:22:23 +0100196 } else {
197 m = await c.send({ embeds: LoadingEmbed });
198 }
pineafan813bdf42022-07-24 10:39:10 +0100199 let page = 0;
200
PineaFan0d06edc2023-01-17 22:10:31 +0000201 const publicFilter = async (component: MessageComponentInteraction) => {
PineaFane6ba7882023-01-18 20:41:16 +0000202 return (component.member as Discord.GuildMember).permissions.has("ManageGuild");
pineafan63fc5e22022-08-04 22:04:10 +0100203 };
pineafan813bdf42022-07-24 10:39:10 +0100204
205 let selectPaneOpen = false;
206
Skyler Greyf21323a2022-08-13 23:58:22 +0100207 let cancelled = false;
208 let timedOut = false;
209 while (!cancelled && !timedOut) {
PineaFane6ba7882023-01-18 20:41:16 +0000210 let selectPane: ActionRowBuilder<Discord.StringSelectMenuBuilder | ButtonBuilder>[] = [];
pineafan813bdf42022-07-24 10:39:10 +0100211
212 if (selectPaneOpen) {
PineaFane6ba7882023-01-18 20:41:16 +0000213 const options: Discord.StringSelectMenuOptionBuilder[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100214 pages.forEach((embed) => {
PineaFane6ba7882023-01-18 20:41:16 +0000215 options.push(new Discord.StringSelectMenuOptionBuilder()
216 .setLabel(embed.title)
217 .setValue(embed.pageId.toString())
218 .setDescription(embed.description || "")
219 );
pineafan63fc5e22022-08-04 22:04:10 +0100220 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100221 selectPane = [
PineaFane6ba7882023-01-18 20:41:16 +0000222 new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents([
223 new Discord.StringSelectMenuBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100224 .addOptions(options)
225 .setCustomId("page")
226 .setMaxValues(1)
227 .setPlaceholder("Choose a page...")
228 ])
229 ];
pineafan813bdf42022-07-24 10:39:10 +0100230 }
PineaFane6ba7882023-01-18 20:41:16 +0000231 const components: ActionRowBuilder<ButtonBuilder | Discord.StringSelectMenuBuilder>[] = selectPane.concat([
232 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProf21c08592022-09-13 14:14:43 -0400233 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100234 .setCustomId("left")
235 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400236 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100237 .setDisabled(page === 0),
TheCodedProf21c08592022-09-13 14:14:43 -0400238 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100239 .setCustomId("select")
240 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400241 .setStyle(selectPaneOpen ? ButtonStyle.Primary : ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100242 .setDisabled(false),
TheCodedProf21c08592022-09-13 14:14:43 -0400243 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100244 .setCustomId("right")
245 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400246 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100247 .setDisabled(page === pages.length - 1)
PineaFane6ba7882023-01-18 20:41:16 +0000248 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100249 ]);
pineafan813bdf42022-07-24 10:39:10 +0100250 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400251 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000252 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan813bdf42022-07-24 10:39:10 +0100253 await interaction.editReply({
254 embeds: [em],
255 components: components
256 });
257 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400258 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000259 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan3a02ea32022-08-11 21:35:04 +0100260 (await m.edit({
pineafan813bdf42022-07-24 10:39:10 +0100261 embeds: [em],
pineafan3a02ea32022-08-11 21:35:04 +0100262 components: components
263 })) as Message;
pineafan813bdf42022-07-24 10:39:10 +0100264 }
pineafan63fc5e22022-08-04 22:04:10 +0100265 let i;
pineafan813bdf42022-07-24 10:39:10 +0100266 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100267 i = await m.awaitMessageComponent({
268 filter: interaction
PineaFan0d06edc2023-01-17 22:10:31 +0000269 ? (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
270 : publicFilter,
Skyler Grey75ea9172022-08-06 10:22:23 +0100271 time: 300000
272 });
273 } catch (e) {
Skyler Greyf21323a2022-08-13 23:58:22 +0100274 timedOut = true;
275 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100276 }
pineafan63fc5e22022-08-04 22:04:10 +0100277 i.deferUpdate();
pineafan3a02ea32022-08-11 21:35:04 +0100278 if (!("customId" in i.component)) {
279 continue;
280 } else if (i.component.customId === "left") {
pineafan813bdf42022-07-24 10:39:10 +0100281 if (page > 0) page--;
282 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100283 } else if (i.component.customId === "right") {
pineafan813bdf42022-07-24 10:39:10 +0100284 if (page < pages.length - 1) page++;
285 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100286 } else if (i.component.customId === "select") {
pineafan813bdf42022-07-24 10:39:10 +0100287 selectPaneOpen = !selectPaneOpen;
pineafane23c4ec2022-07-27 21:56:27 +0100288 } else if (i.component.customId === "page") {
PineaFane6ba7882023-01-18 20:41:16 +0000289 page = parseInt((i as StringSelectMenuInteraction).values[0]!);
pineafan813bdf42022-07-24 10:39:10 +0100290 selectPaneOpen = false;
291 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100292 cancelled = true;
pineafan813bdf42022-07-24 10:39:10 +0100293 }
294 }
Skyler Greyf21323a2022-08-13 23:58:22 +0100295 if (timedOut) {
296 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400297 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000298 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100299 text: "Message timed out"
300 });
301 await interaction.editReply({
302 embeds: [em],
303 components: []
304 });
305 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400306 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000307 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100308 text: "Message timed out"
309 });
310 await m.edit({
311 embeds: [em],
312 components: []
313 });
314 }
pineafan813bdf42022-07-24 10:39:10 +0100315 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100316 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400317 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000318 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
Skyler Greyf21323a2022-08-13 23:58:22 +0100319 em.setFooter({ text: "Message closed" });
320 interaction.editReply({
321 embeds: [em],
322 components: []
323 });
324 } else {
325 m.delete();
326 }
pineafan813bdf42022-07-24 10:39:10 +0100327 }
pineafan63fc5e22022-08-04 22:04:10 +0100328};