blob: 93978e64637b0c5a4a764a7bf81ccb851fb79cc6 [file] [log] [blame]
Skyler Greyda16adf2023-03-05 10:22:12 +00001import { getCommandMentionByName } from "./../utils/getCommandDataByName.js";
PineaFan0d06edc2023-01-17 22:10:31 +00002import { LoadingEmbed } from "../utils/defaults.js";
pineafan3a02ea32022-08-11 21:35:04 +01003import Discord, {
TheCodedProf21c08592022-09-13 14:14:43 -04004 ActionRowBuilder,
5 ButtonBuilder,
pineafan3a02ea32022-08-11 21:35:04 +01006 MessageComponentInteraction,
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
pineafandef38a72023-05-28 12:47:36 +010019export default async (guild: Guild | null, interaction?: CommandInteraction) => {
PineaFand471ccd2023-01-26 20:48:40 +000020 let m: Message;
pineafandef38a72023-05-28 12:47:36 +010021 if (guild) {
pineafan72659cc2023-05-28 13:36:44 +010022 let c: GuildTextBasedChannel | null = guild.publicUpdatesChannel
23 ? guild.publicUpdatesChannel
24 : guild.systemChannel;
pineafandef38a72023-05-28 12:47:36 +010025 c = c
26 ? c
27 : (guild.channels.cache.find(
pineafan72659cc2023-05-28 13:36:44 +010028 (ch) =>
29 [
30 ChannelType.GuildText,
31 ChannelType.GuildAnnouncement,
32 ChannelType.PublicThread,
33 ChannelType.PrivateThread,
34 ChannelType.AnnouncementThread
35 ].includes(ch.type) &&
36 ch.permissionsFor(guild.roles.everyone).has("SendMessages") &&
37 ch.permissionsFor(guild.members.me!).has("EmbedLinks")
38 ) as GuildTextBasedChannel | undefined) ?? null;
pineafandef38a72023-05-28 12:47:36 +010039 if (interaction) c = interaction.channel as GuildTextBasedChannel;
40 if (!c) {
41 return;
42 }
43 if (interaction) {
44 m = (await interaction.reply({
45 embeds: LoadingEmbed,
46 fetchReply: true,
47 ephemeral: true
48 })) as Message;
49 } else {
50 m = await c.send({ embeds: LoadingEmbed });
51 }
PineaFand471ccd2023-01-26 20:48:40 +000052 } else {
pineafandef38a72023-05-28 12:47:36 +010053 if (interaction) {
54 m = (await interaction.reply({
55 embeds: LoadingEmbed,
56 fetchReply: true,
57 ephemeral: true
58 })) as Message;
59 } else {
60 return;
61 }
PineaFand471ccd2023-01-26 20:48:40 +000062 }
63 let page = 0;
pineafan63fc5e22022-08-04 22:04:10 +010064 const pages = [
pineafan813bdf42022-07-24 10:39:10 +010065 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010066 .setEmbed(
67 new EmojiEmbed()
68 .setTitle("Welcome to Nucleus")
69 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +000070 "Thanks for adding Nucleus to your server!\n\n" +
71 "The next few pages will show what features Nucleus has to offer, and how to enable them.\n\n" +
72 "If you need support, have questions or want features, you can let us know in [Clicks](https://discord.gg/bPaNnxe)!"
Skyler Grey75ea9172022-08-06 10:22:23 +010073 )
74 .setEmoji("NUCLEUS.LOGO")
75 .setStatus("Danger")
76 )
77 .setTitle("Welcome")
78 .setDescription("About Nucleus")
79 .setPageId(0),
pineafan813bdf42022-07-24 10:39:10 +010080 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010081 .setEmbed(
82 new EmojiEmbed()
PineaFand471ccd2023-01-26 20:48:40 +000083 .setTitle("Logs")
Skyler Grey75ea9172022-08-06 10:22:23 +010084 .setDescription(
85 "Nucleus can log server events and keep you informed with what content is being posted to your server.\n" +
86 "We have 2 different types of logs, which each can be configured to send to a channel of your choice:\n" +
PineaFand471ccd2023-01-26 20:48:40 +000087 "**General:** These are events like kicks and channel changes etc.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +000088 `> These are standard logs and can be set with ${getCommandMentionByName(
89 "settings/logs/general"
90 )}\n` +
PineaFand471ccd2023-01-26 20:48:40 +000091 "**Warnings:** Warnings like NSFW avatars and spam etc. that may require action by a server staff member.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +000092 `> These may require special action by a moderator. You can set the channel with ${getCommandMentionByName(
93 "settings/logs/warnings"
94 )}\n` +
PineaFand471ccd2023-01-26 20:48:40 +000095 "**Attachments:** All images sent in the server - Used to keep a record of deleted images\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +000096 `> Sent to a separate log channel to avoid spam. This can be set with ${getCommandMentionByName(
97 "settings/logs/attachments"
98 )}\n` +
99 `> ${getEmojiByName(
100 "NUCLEUS.PREMIUM"
101 )} Please note this feature is only available with ${getCommandMentionByName(
102 "nucleus/premium"
103 )}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100104 )
105 .setEmoji("ICONS.LOGGING")
106 .setStatus("Danger")
107 )
108 .setTitle("Logging")
109 .setDescription("Logging, staff warning logs etc.")
110 .setPageId(1),
pineafan813bdf42022-07-24 10:39:10 +0100111 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 .setEmbed(
113 new EmojiEmbed()
114 .setTitle("Moderation")
115 .setDescription(
116 "Nucleus has a number of commands that can be used to moderate your server.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000117 `These commands are all found under ${getCommandMentionByName(
118 "mod"
119 )}, and they include:\n` +
120 `${getEmojiByName("PUNISH.WARN.YELLOW")} ${getCommandMentionByName(
121 "mod/warn"
122 )}: The user is warned (via DM) that they violated server rules. More options given if DMs are disabled.\n` +
123 `${getEmojiByName("PUNISH.CLEARHISTORY")} ${getCommandMentionByName(
124 "mod/purge"
125 )}: Deletes messages in a channel, giving options to only delete messages by a certain user.\n` +
126 `${getEmojiByName("PUNISH.MUTE.YELLOW")} ${getCommandMentionByName(
127 "mod/mute"
128 )}: Stops users sending messages or joining voice chats.\n` +
129 `${getEmojiByName("PUNISH.MUTE.GREEN")} ${getCommandMentionByName(
130 "mod/unmute"
131 )}: Allows user to send messages and join voice chats.\n` +
132 `${getEmojiByName("PUNISH.KICK.RED")} ${getCommandMentionByName(
133 "mod/kick"
134 )}: Removes a member from the server. They will be able to rejoin.\n` +
135 `${getEmojiByName("PUNISH.SOFTBAN")} ${getCommandMentionByName(
136 "mod/softban"
137 )}: Kicks the user, deleting their messages from every channel in a given time frame.\n` +
138 `${getEmojiByName("PUNISH.BAN.RED")} ${getCommandMentionByName(
139 "mod/ban"
140 )}: Removes the user from the server, deleting messages from every channel and stops them from rejoining.\n` +
141 `${getEmojiByName("PUNISH.BAN.GREEN")} ${getCommandMentionByName(
142 "mod/unban"
143 )}: Allows a member to rejoin the server after being banned.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100144 )
145 .setEmoji("PUNISH.BAN.RED")
146 .setStatus("Danger")
147 )
148 .setTitle("Moderation")
149 .setDescription("Basic moderation commands")
150 .setPageId(2),
pineafan813bdf42022-07-24 10:39:10 +0100151 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100152 .setEmbed(
153 new EmojiEmbed()
154 .setTitle("Verify")
155 .setDescription(
156 "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000157 `This is done by running ${getCommandMentionByName(
158 "verify"
159 )} which sends a message only the user can see, giving them a link to a website to verify.\n` +
PineaFand471ccd2023-01-26 20:48:40 +0000160 "After the user complete's the check, they are given a role, which can be set to unlock specific channels.\n" +
TheCodedProff86ba092023-01-27 17:10:07 -0500161 `You can set the role given with ${getCommandMentionByName("settings/verify")}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100162 )
163 .setEmoji("CONTROL.REDTICK")
164 .setStatus("Danger")
165 )
166 .setTitle("Verify")
167 .setDescription("Captcha verification system")
168 .setPageId(3),
pineafan813bdf42022-07-24 10:39:10 +0100169 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100170 .setEmbed(
171 new EmojiEmbed()
172 .setTitle("Content Scanning")
173 .setDescription(
174 "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
PineaFand471ccd2023-01-26 20:48:40 +0000175 "The staff team can be notified when an NSFW image is detected, or malicious links are sent.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000176 `You can check and manage what to moderate in ${getCommandMentionByName(
177 "settings/automod"
178 )}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100179 )
180 .setEmoji("MOD.IMAGES.TOOSMALL")
181 .setStatus("Danger")
182 )
183 .setTitle("Content Scanning")
184 .setDescription("Content (NSFW, malware, scams) scanning")
185 .setPageId(4),
pineafan813bdf42022-07-24 10:39:10 +0100186 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100187 .setEmbed(
188 new EmojiEmbed()
189 .setTitle("Tickets")
190 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000191 "Nucleus has a ticket system which allows users to create tickets and talk to the server staff or support team.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000192 `Tickets can be created by users with ${getCommandMentionByName(
193 "ticket/create"
194 )}, or by clicking a button created by moderators.\n` +
PineaFand471ccd2023-01-26 20:48:40 +0000195 `After being created, a new channel or thread is created, and the user and support team are pinged. \n` +
Skyler Greyda16adf2023-03-05 10:22:12 +0000196 `The category or channel to create threads in can be set with ${getCommandMentionByName(
197 "settings/tickets"
198 )}\n` +
199 `When the ticket is resolved, anyone can run ${getCommandMentionByName(
200 "ticket/close"
201 )} (or click the button) to close it.\n` +
TheCodedProff86ba092023-01-27 17:10:07 -0500202 `Running ${getCommandMentionByName("ticket/close")} again will delete the ticket.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100203 )
204 .setEmoji("GUILD.TICKET.CLOSE")
205 .setStatus("Danger")
206 )
207 .setTitle("Tickets")
208 .setDescription("Ticket system")
209 .setPageId(5),
pineafan813bdf42022-07-24 10:39:10 +0100210 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100211 .setEmbed(
212 new EmojiEmbed()
213 .setTitle("Tags")
214 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000215 "Nucleus allows you to create tags, which allow a message to be sent when a specific tag is typed.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000216 `Tags can be created with ${getCommandMentionByName(
217 "tags/create"
218 )}, and can be edited with ${getCommandMentionByName("tags/edit")}\n` +
219 `Tags can be deleted with ${getCommandMentionByName(
220 "tags/delete"
221 )}, and can be listed with ${getCommandMentionByName("tags/list")}\n` +
TheCodedProff86ba092023-01-27 17:10:07 -0500222 `To use a tag, you can type ${getCommandMentionByName("tag")}, followed by the tag to send`
Skyler Grey75ea9172022-08-06 10:22:23 +0100223 )
224 .setEmoji("PUNISH.NICKNAME.RED")
225 .setStatus("Danger")
226 )
227 .setTitle("Tags")
228 .setDescription("Tag system")
229 .setPageId(6),
pineafan813bdf42022-07-24 10:39:10 +0100230 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100231 .setEmbed(
232 new EmojiEmbed()
233 .setTitle("Premium")
234 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000235 "Nucleus Premium allows you to use extra features in your server, which are useful but not essential.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000236 "**No currently free commands will become premium features.**\n" +
237 "Premium features include creating ticket transcripts and attachment logs.\n\n" +
238 "Premium can be purchased in [our server](https://discord.gg/bPaNnxe) in the subscriptions page" // TODO: add a table graphic
Skyler Grey75ea9172022-08-06 10:22:23 +0100239 )
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500240 .setEmoji("NUCLEUS.PREMIUM")
Skyler Grey75ea9172022-08-06 10:22:23 +0100241 .setStatus("Danger")
242 )
243 .setTitle("Premium")
244 .setDescription("Premium features")
245 .setPageId(7)
pineafan63fc5e22022-08-04 22:04:10 +0100246 ];
pineafan813bdf42022-07-24 10:39:10 +0100247
PineaFan0d06edc2023-01-17 22:10:31 +0000248 const publicFilter = async (component: MessageComponentInteraction) => {
PineaFane6ba7882023-01-18 20:41:16 +0000249 return (component.member as Discord.GuildMember).permissions.has("ManageGuild");
pineafan63fc5e22022-08-04 22:04:10 +0100250 };
pineafan813bdf42022-07-24 10:39:10 +0100251
252 let selectPaneOpen = false;
253
Skyler Greyf21323a2022-08-13 23:58:22 +0100254 let cancelled = false;
255 let timedOut = false;
256 while (!cancelled && !timedOut) {
PineaFane6ba7882023-01-18 20:41:16 +0000257 let selectPane: ActionRowBuilder<Discord.StringSelectMenuBuilder | ButtonBuilder>[] = [];
pineafan813bdf42022-07-24 10:39:10 +0100258
259 if (selectPaneOpen) {
PineaFane6ba7882023-01-18 20:41:16 +0000260 const options: Discord.StringSelectMenuOptionBuilder[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100261 pages.forEach((embed) => {
Skyler Greyda16adf2023-03-05 10:22:12 +0000262 options.push(
263 new Discord.StringSelectMenuOptionBuilder()
264 .setLabel(embed.title)
265 .setValue(embed.pageId.toString())
266 .setDescription(embed.description || "")
PineaFane6ba7882023-01-18 20:41:16 +0000267 );
pineafan63fc5e22022-08-04 22:04:10 +0100268 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100269 selectPane = [
PineaFane6ba7882023-01-18 20:41:16 +0000270 new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents([
271 new Discord.StringSelectMenuBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100272 .addOptions(options)
273 .setCustomId("page")
274 .setMaxValues(1)
275 .setPlaceholder("Choose a page...")
276 ])
277 ];
pineafan813bdf42022-07-24 10:39:10 +0100278 }
PineaFane6ba7882023-01-18 20:41:16 +0000279 const components: ActionRowBuilder<ButtonBuilder | Discord.StringSelectMenuBuilder>[] = selectPane.concat([
280 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProf21c08592022-09-13 14:14:43 -0400281 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100282 .setCustomId("left")
283 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400284 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100285 .setDisabled(page === 0),
TheCodedProf21c08592022-09-13 14:14:43 -0400286 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100287 .setCustomId("select")
288 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400289 .setStyle(selectPaneOpen ? ButtonStyle.Primary : ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100290 .setDisabled(false),
TheCodedProf21c08592022-09-13 14:14:43 -0400291 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100292 .setCustomId("right")
293 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400294 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100295 .setDisabled(page === pages.length - 1)
PineaFane6ba7882023-01-18 20:41:16 +0000296 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100297 ]);
pineafan813bdf42022-07-24 10:39:10 +0100298 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400299 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000300 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan813bdf42022-07-24 10:39:10 +0100301 await interaction.editReply({
302 embeds: [em],
303 components: 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));
pineafan3a02ea32022-08-11 21:35:04 +0100308 (await m.edit({
pineafan813bdf42022-07-24 10:39:10 +0100309 embeds: [em],
pineafan3a02ea32022-08-11 21:35:04 +0100310 components: components
311 })) as Message;
pineafan813bdf42022-07-24 10:39:10 +0100312 }
pineafan63fc5e22022-08-04 22:04:10 +0100313 let i;
pineafan813bdf42022-07-24 10:39:10 +0100314 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100315 i = await m.awaitMessageComponent({
316 filter: interaction
Skyler Greyda16adf2023-03-05 10:22:12 +0000317 ? (i) => {
318 return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id;
319 }
PineaFan0d06edc2023-01-17 22:10:31 +0000320 : publicFilter,
Skyler Grey75ea9172022-08-06 10:22:23 +0100321 time: 300000
322 });
323 } catch (e) {
Skyler Greyf21323a2022-08-13 23:58:22 +0100324 timedOut = true;
325 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100326 }
TheCodedProf267563a2023-01-21 17:00:57 -0500327 await i.deferUpdate();
pineafan3a02ea32022-08-11 21:35:04 +0100328 if (!("customId" in i.component)) {
329 continue;
330 } else if (i.component.customId === "left") {
pineafan813bdf42022-07-24 10:39:10 +0100331 if (page > 0) page--;
332 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100333 } else if (i.component.customId === "right") {
pineafan813bdf42022-07-24 10:39:10 +0100334 if (page < pages.length - 1) page++;
335 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100336 } else if (i.component.customId === "select") {
pineafan813bdf42022-07-24 10:39:10 +0100337 selectPaneOpen = !selectPaneOpen;
TheCodedProf4a6d5712023-01-19 15:54:40 -0500338 } else if (i.isStringSelectMenu() && i.component.customId === "page") {
339 page = parseInt(i.values[0]!);
pineafan813bdf42022-07-24 10:39:10 +0100340 selectPaneOpen = false;
341 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100342 cancelled = true;
pineafan813bdf42022-07-24 10:39:10 +0100343 }
344 }
Skyler Greyf21323a2022-08-13 23:58:22 +0100345 if (timedOut) {
346 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400347 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000348 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100349 text: "Message timed out"
350 });
351 await interaction.editReply({
352 embeds: [em],
353 components: []
354 });
355 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400356 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000357 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100358 text: "Message timed out"
359 });
360 await m.edit({
361 embeds: [em],
362 components: []
363 });
364 }
pineafan813bdf42022-07-24 10:39:10 +0100365 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100366 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400367 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000368 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
Skyler Greyf21323a2022-08-13 23:58:22 +0100369 em.setFooter({ text: "Message closed" });
Skyler Greyf4f21c42023-03-08 14:36:29 +0000370 await interaction.editReply({
Skyler Greyf21323a2022-08-13 23:58:22 +0100371 embeds: [em],
372 components: []
373 });
374 } else {
Skyler Greyf4f21c42023-03-08 14:36:29 +0000375 await m.delete();
Skyler Greyf21323a2022-08-13 23:58:22 +0100376 }
pineafan813bdf42022-07-24 10:39:10 +0100377 }
pineafan63fc5e22022-08-04 22:04:10 +0100378};