blob: a3027e4a14e73203dc4ec6932d779345bfc66ccd [file] [log] [blame]
Samuel Shuert27bf3cd2023-03-03 15:51:25 -05001import { 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
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
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050022 ? c
23 : (guild.channels.cache.find(
24 (ch) =>
25 [
26 ChannelType.GuildText,
27 ChannelType.GuildAnnouncement,
28 ChannelType.PublicThread,
29 ChannelType.PrivateThread,
30 ChannelType.AnnouncementThread
31 ].includes(ch.type) &&
32 ch.permissionsFor(guild.roles.everyone).has("SendMessages") &&
33 ch.permissionsFor(guild.members.me!).has("EmbedLinks")
34 ) as GuildTextBasedChannel | undefined) ?? null;
pineafan3a02ea32022-08-11 21:35:04 +010035 if (interaction) c = interaction.channel as GuildTextBasedChannel;
36 if (!c) {
37 return;
38 }
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050039 let m: Message;
40 if (interaction) {
41 m = (await interaction.reply({
42 embeds: LoadingEmbed,
43 fetchReply: true,
44 ephemeral: true
45 })) as Message;
46 } else {
47 m = await c.send({ embeds: LoadingEmbed });
48 }
49 let page = 0;
pineafan63fc5e22022-08-04 22:04:10 +010050 const pages = [
pineafan813bdf42022-07-24 10:39:10 +010051 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010052 .setEmbed(
53 new EmojiEmbed()
54 .setTitle("Welcome to Nucleus")
55 .setDescription(
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050056 "Thanks for adding Nucleus to your server!\n\n" +
57 "The next few pages will show what features Nucleus has to offer, and how to enable them.\n\n" +
58 "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 +010059 )
60 .setEmoji("NUCLEUS.LOGO")
61 .setStatus("Danger")
62 )
63 .setTitle("Welcome")
64 .setDescription("About Nucleus")
65 .setPageId(0),
pineafan813bdf42022-07-24 10:39:10 +010066 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010067 .setEmbed(
68 new EmojiEmbed()
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050069 .setTitle("Logs")
Skyler Grey75ea9172022-08-06 10:22:23 +010070 .setDescription(
71 "Nucleus can log server events and keep you informed with what content is being posted to your server.\n" +
72 "We have 2 different types of logs, which each can be configured to send to a channel of your choice:\n" +
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050073 "**General:** These are events like kicks and channel changes etc.\n" +
74 `> These are standard logs and can be set with ${getCommandMentionByName("settings/logs/general")}\n` +
75 "**Warnings:** Warnings like NSFW avatars and spam etc. that may require action by a server staff member.\n" +
76 `> These may require special action by a moderator. You can set the channel with ${getCommandMentionByName("settings/logs/warnings")}\n` +
77 "**Attachments:** All images sent in the server - Used to keep a record of deleted images\n" +
78 `> Sent to a separate log channel to avoid spam. This can be set with ${getCommandMentionByName("settings/logs/attachments")}\n` +
79 `> ${getEmojiByName("NUCLEUS.PREMIUM")} Please note this feature is only available with ${getCommandMentionByName("nucleus/premium")}`
Skyler Grey75ea9172022-08-06 10:22:23 +010080 )
81 .setEmoji("ICONS.LOGGING")
82 .setStatus("Danger")
83 )
84 .setTitle("Logging")
85 .setDescription("Logging, staff warning logs etc.")
86 .setPageId(1),
pineafan813bdf42022-07-24 10:39:10 +010087 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010088 .setEmbed(
89 new EmojiEmbed()
90 .setTitle("Moderation")
91 .setDescription(
92 "Nucleus has a number of commands that can be used to moderate your server.\n" +
Samuel Shuert27bf3cd2023-03-03 15:51:25 -050093 `These commands are all found under ${getCommandMentionByName(("mod"))}, and they include:\n` +
94 `${getEmojiByName("PUNISH.WARN.YELLOW")} ${getCommandMentionByName("mod/warn")}: The user is warned (via DM) that they violated server rules. More options given if DMs are disabled.\n` +
95 `${getEmojiByName("PUNISH.CLEARHISTORY")} ${getCommandMentionByName("mod/purge")}: Deletes messages in a channel, giving options to only delete messages by a certain user.\n` +
96 `${getEmojiByName("PUNISH.MUTE.YELLOW")} ${getCommandMentionByName("mod/mute")}: Stops users sending messages or joining voice chats.\n` +
97 `${getEmojiByName("PUNISH.MUTE.GREEN")} ${getCommandMentionByName("mod/unmute")}: Allows user to send messages and join voice chats.\n` +
98 `${getEmojiByName("PUNISH.KICK.RED")} ${getCommandMentionByName("mod/kick")}: Removes a member from the server. They will be able to rejoin.\n` +
99 `${getEmojiByName("PUNISH.SOFTBAN")} ${getCommandMentionByName("mod/softban")}: Kicks the user, deleting their messages from every channel in a given time frame.\n` +
100 `${getEmojiByName("PUNISH.BAN.RED")} ${getCommandMentionByName("mod/ban")}: Removes the user from the server, deleting messages from every channel and stops them from rejoining.\n` +
101 `${getEmojiByName("PUNISH.BAN.GREEN")} ${getCommandMentionByName("mod/unban")}: Allows a member to rejoin the server after being banned.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100102 )
103 .setEmoji("PUNISH.BAN.RED")
104 .setStatus("Danger")
105 )
106 .setTitle("Moderation")
107 .setDescription("Basic moderation commands")
108 .setPageId(2),
pineafan813bdf42022-07-24 10:39:10 +0100109 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100110 .setEmbed(
111 new EmojiEmbed()
112 .setTitle("Verify")
113 .setDescription(
114 "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500115 `This is done by running ${getCommandMentionByName("verify")} which sends a message only the user can see, giving them a link to a website to verify.\n` +
116 "After the user complete's the check, they are given a role, which can be set to unlock specific channels.\n" +
117 `You can set the role given with ${getCommandMentionByName("settings/verify")}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100118 )
119 .setEmoji("CONTROL.REDTICK")
120 .setStatus("Danger")
121 )
122 .setTitle("Verify")
123 .setDescription("Captcha verification system")
124 .setPageId(3),
pineafan813bdf42022-07-24 10:39:10 +0100125 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 .setEmbed(
127 new EmojiEmbed()
128 .setTitle("Content Scanning")
129 .setDescription(
130 "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500131 "The staff team can be notified when an NSFW image is detected, or malicious links are sent.\n" +
132 `You can check and manage what to moderate in ${getCommandMentionByName("settings/automod")}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100133 )
134 .setEmoji("MOD.IMAGES.TOOSMALL")
135 .setStatus("Danger")
136 )
137 .setTitle("Content Scanning")
138 .setDescription("Content (NSFW, malware, scams) scanning")
139 .setPageId(4),
pineafan813bdf42022-07-24 10:39:10 +0100140 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100141 .setEmbed(
142 new EmojiEmbed()
143 .setTitle("Tickets")
144 .setDescription(
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500145 "Nucleus has a ticket system which allows users to create tickets and talk to the server staff or support team.\n" +
146 `Tickets can be created by users with ${getCommandMentionByName("ticket/create")}, or by clicking a button created by moderators.\n` +
147 `After being created, a new channel or thread is created, and the user and support team are pinged. \n` +
148 `The category or channel to create threads in can be set with ${getCommandMentionByName("settings/tickets")}\n` +
149 `When the ticket is resolved, anyone can run ${getCommandMentionByName("ticket/close")} (or click the button) to close it.\n` +
150 `Running ${getCommandMentionByName("ticket/close")} again will delete the ticket.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100151 )
152 .setEmoji("GUILD.TICKET.CLOSE")
153 .setStatus("Danger")
154 )
155 .setTitle("Tickets")
156 .setDescription("Ticket system")
157 .setPageId(5),
pineafan813bdf42022-07-24 10:39:10 +0100158 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100159 .setEmbed(
160 new EmojiEmbed()
161 .setTitle("Tags")
162 .setDescription(
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500163 "Nucleus allows you to create tags, which allow a message to be sent when a specific tag is typed.\n" +
164 `Tags can be created with ${getCommandMentionByName("tags/create")}, and can be edited with ${getCommandMentionByName("tags/edit")}\n` +
165 `Tags can be deleted with ${getCommandMentionByName("tags/delete")}, and can be listed with ${getCommandMentionByName("tags/list")}\n` +
166 `To use a tag, you can type ${getCommandMentionByName("tag")}, followed by the tag to send`
Skyler Grey75ea9172022-08-06 10:22:23 +0100167 )
168 .setEmoji("PUNISH.NICKNAME.RED")
169 .setStatus("Danger")
170 )
171 .setTitle("Tags")
172 .setDescription("Tag system")
173 .setPageId(6),
pineafan813bdf42022-07-24 10:39:10 +0100174 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100175 .setEmbed(
176 new EmojiEmbed()
177 .setTitle("Premium")
178 .setDescription(
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500179 "Nucleus Premium allows you to use extra features in your server, which are useful but not essential.\n" +
180 "**No currently free commands will become premium features.**\n" +
181 "Premium features include creating ticket transcripts and attachment logs.\n\n" +
182 "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 +0100183 )
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500184 .setEmoji("NUCLEUS.PREMIUM")
Skyler Grey75ea9172022-08-06 10:22:23 +0100185 .setStatus("Danger")
186 )
187 .setTitle("Premium")
188 .setDescription("Premium features")
189 .setPageId(7)
pineafan63fc5e22022-08-04 22:04:10 +0100190 ];
pineafan813bdf42022-07-24 10:39:10 +0100191
PineaFan0d06edc2023-01-17 22:10:31 +0000192 const publicFilter = async (component: MessageComponentInteraction) => {
PineaFane6ba7882023-01-18 20:41:16 +0000193 return (component.member as Discord.GuildMember).permissions.has("ManageGuild");
pineafan63fc5e22022-08-04 22:04:10 +0100194 };
pineafan813bdf42022-07-24 10:39:10 +0100195
196 let selectPaneOpen = false;
197
Skyler Greyf21323a2022-08-13 23:58:22 +0100198 let cancelled = false;
199 let timedOut = false;
200 while (!cancelled && !timedOut) {
PineaFane6ba7882023-01-18 20:41:16 +0000201 let selectPane: ActionRowBuilder<Discord.StringSelectMenuBuilder | ButtonBuilder>[] = [];
pineafan813bdf42022-07-24 10:39:10 +0100202
203 if (selectPaneOpen) {
PineaFane6ba7882023-01-18 20:41:16 +0000204 const options: Discord.StringSelectMenuOptionBuilder[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100205 pages.forEach((embed) => {
PineaFane6ba7882023-01-18 20:41:16 +0000206 options.push(new Discord.StringSelectMenuOptionBuilder()
207 .setLabel(embed.title)
208 .setValue(embed.pageId.toString())
209 .setDescription(embed.description || "")
210 );
pineafan63fc5e22022-08-04 22:04:10 +0100211 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100212 selectPane = [
PineaFane6ba7882023-01-18 20:41:16 +0000213 new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents([
214 new Discord.StringSelectMenuBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100215 .addOptions(options)
216 .setCustomId("page")
217 .setMaxValues(1)
218 .setPlaceholder("Choose a page...")
219 ])
220 ];
pineafan813bdf42022-07-24 10:39:10 +0100221 }
PineaFane6ba7882023-01-18 20:41:16 +0000222 const components: ActionRowBuilder<ButtonBuilder | Discord.StringSelectMenuBuilder>[] = selectPane.concat([
223 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProf21c08592022-09-13 14:14:43 -0400224 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100225 .setCustomId("left")
226 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400227 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100228 .setDisabled(page === 0),
TheCodedProf21c08592022-09-13 14:14:43 -0400229 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100230 .setCustomId("select")
231 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400232 .setStyle(selectPaneOpen ? ButtonStyle.Primary : ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100233 .setDisabled(false),
TheCodedProf21c08592022-09-13 14:14:43 -0400234 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100235 .setCustomId("right")
236 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400237 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100238 .setDisabled(page === pages.length - 1)
PineaFane6ba7882023-01-18 20:41:16 +0000239 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100240 ]);
pineafan813bdf42022-07-24 10:39:10 +0100241 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400242 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000243 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan813bdf42022-07-24 10:39:10 +0100244 await interaction.editReply({
245 embeds: [em],
246 components: components
247 });
248 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400249 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000250 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan3a02ea32022-08-11 21:35:04 +0100251 (await m.edit({
pineafan813bdf42022-07-24 10:39:10 +0100252 embeds: [em],
pineafan3a02ea32022-08-11 21:35:04 +0100253 components: components
254 })) as Message;
pineafan813bdf42022-07-24 10:39:10 +0100255 }
pineafan63fc5e22022-08-04 22:04:10 +0100256 let i;
pineafan813bdf42022-07-24 10:39:10 +0100257 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100258 i = await m.awaitMessageComponent({
259 filter: interaction
PineaFan0d06edc2023-01-17 22:10:31 +0000260 ? (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
261 : publicFilter,
Skyler Grey75ea9172022-08-06 10:22:23 +0100262 time: 300000
263 });
264 } catch (e) {
Skyler Greyf21323a2022-08-13 23:58:22 +0100265 timedOut = true;
266 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100267 }
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500268 await i.deferUpdate();
pineafan3a02ea32022-08-11 21:35:04 +0100269 if (!("customId" in i.component)) {
270 continue;
271 } else if (i.component.customId === "left") {
pineafan813bdf42022-07-24 10:39:10 +0100272 if (page > 0) page--;
273 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100274 } else if (i.component.customId === "right") {
pineafan813bdf42022-07-24 10:39:10 +0100275 if (page < pages.length - 1) page++;
276 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100277 } else if (i.component.customId === "select") {
pineafan813bdf42022-07-24 10:39:10 +0100278 selectPaneOpen = !selectPaneOpen;
Samuel Shuert27bf3cd2023-03-03 15:51:25 -0500279 } else if (i.isStringSelectMenu() && i.component.customId === "page") {
280 page = parseInt(i.values[0]!);
pineafan813bdf42022-07-24 10:39:10 +0100281 selectPaneOpen = false;
282 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100283 cancelled = true;
pineafan813bdf42022-07-24 10:39:10 +0100284 }
285 }
Skyler Greyf21323a2022-08-13 23:58:22 +0100286 if (timedOut) {
287 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400288 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000289 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100290 text: "Message timed out"
291 });
292 await interaction.editReply({
293 embeds: [em],
294 components: []
295 });
296 } else {
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 m.edit({
302 embeds: [em],
303 components: []
304 });
305 }
pineafan813bdf42022-07-24 10:39:10 +0100306 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100307 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400308 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000309 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
Skyler Greyf21323a2022-08-13 23:58:22 +0100310 em.setFooter({ text: "Message closed" });
311 interaction.editReply({
312 embeds: [em],
313 components: []
314 });
315 } else {
316 m.delete();
317 }
pineafan813bdf42022-07-24 10:39:10 +0100318 }
pineafan63fc5e22022-08-04 22:04:10 +0100319};