blob: 59c12c7b3affebf27913ea9a3a80d9371ae7184a [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
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
Skyler Greyda16adf2023-03-05 10:22:12 +000022 ? 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 }
PineaFand471ccd2023-01-26 20:48:40 +000039 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(
PineaFand471ccd2023-01-26 20:48:40 +000056 "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()
PineaFand471ccd2023-01-26 20:48:40 +000069 .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" +
PineaFand471ccd2023-01-26 20:48:40 +000073 "**General:** These are events like kicks and channel changes etc.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +000074 `> These are standard logs and can be set with ${getCommandMentionByName(
75 "settings/logs/general"
76 )}\n` +
PineaFand471ccd2023-01-26 20:48:40 +000077 "**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 +000078 `> These may require special action by a moderator. You can set the channel with ${getCommandMentionByName(
79 "settings/logs/warnings"
80 )}\n` +
PineaFand471ccd2023-01-26 20:48:40 +000081 "**Attachments:** All images sent in the server - Used to keep a record of deleted images\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +000082 `> Sent to a separate log channel to avoid spam. This can be set with ${getCommandMentionByName(
83 "settings/logs/attachments"
84 )}\n` +
85 `> ${getEmojiByName(
86 "NUCLEUS.PREMIUM"
87 )} Please note this feature is only available with ${getCommandMentionByName(
88 "nucleus/premium"
89 )}`
Skyler Grey75ea9172022-08-06 10:22:23 +010090 )
91 .setEmoji("ICONS.LOGGING")
92 .setStatus("Danger")
93 )
94 .setTitle("Logging")
95 .setDescription("Logging, staff warning logs etc.")
96 .setPageId(1),
pineafan813bdf42022-07-24 10:39:10 +010097 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +010098 .setEmbed(
99 new EmojiEmbed()
100 .setTitle("Moderation")
101 .setDescription(
102 "Nucleus has a number of commands that can be used to moderate your server.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000103 `These commands are all found under ${getCommandMentionByName(
104 "mod"
105 )}, and they include:\n` +
106 `${getEmojiByName("PUNISH.WARN.YELLOW")} ${getCommandMentionByName(
107 "mod/warn"
108 )}: The user is warned (via DM) that they violated server rules. More options given if DMs are disabled.\n` +
109 `${getEmojiByName("PUNISH.CLEARHISTORY")} ${getCommandMentionByName(
110 "mod/purge"
111 )}: Deletes messages in a channel, giving options to only delete messages by a certain user.\n` +
112 `${getEmojiByName("PUNISH.MUTE.YELLOW")} ${getCommandMentionByName(
113 "mod/mute"
114 )}: Stops users sending messages or joining voice chats.\n` +
115 `${getEmojiByName("PUNISH.MUTE.GREEN")} ${getCommandMentionByName(
116 "mod/unmute"
117 )}: Allows user to send messages and join voice chats.\n` +
118 `${getEmojiByName("PUNISH.KICK.RED")} ${getCommandMentionByName(
119 "mod/kick"
120 )}: Removes a member from the server. They will be able to rejoin.\n` +
121 `${getEmojiByName("PUNISH.SOFTBAN")} ${getCommandMentionByName(
122 "mod/softban"
123 )}: Kicks the user, deleting their messages from every channel in a given time frame.\n` +
124 `${getEmojiByName("PUNISH.BAN.RED")} ${getCommandMentionByName(
125 "mod/ban"
126 )}: Removes the user from the server, deleting messages from every channel and stops them from rejoining.\n` +
127 `${getEmojiByName("PUNISH.BAN.GREEN")} ${getCommandMentionByName(
128 "mod/unban"
129 )}: Allows a member to rejoin the server after being banned.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100130 )
131 .setEmoji("PUNISH.BAN.RED")
132 .setStatus("Danger")
133 )
134 .setTitle("Moderation")
135 .setDescription("Basic moderation commands")
136 .setPageId(2),
pineafan813bdf42022-07-24 10:39:10 +0100137 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100138 .setEmbed(
139 new EmojiEmbed()
140 .setTitle("Verify")
141 .setDescription(
142 "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
Skyler Greyda16adf2023-03-05 10:22:12 +0000143 `This is done by running ${getCommandMentionByName(
144 "verify"
145 )} 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 +0000146 "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 -0500147 `You can set the role given with ${getCommandMentionByName("settings/verify")}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100148 )
149 .setEmoji("CONTROL.REDTICK")
150 .setStatus("Danger")
151 )
152 .setTitle("Verify")
153 .setDescription("Captcha verification system")
154 .setPageId(3),
pineafan813bdf42022-07-24 10:39:10 +0100155 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100156 .setEmbed(
157 new EmojiEmbed()
158 .setTitle("Content Scanning")
159 .setDescription(
160 "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
PineaFand471ccd2023-01-26 20:48:40 +0000161 "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 +0000162 `You can check and manage what to moderate in ${getCommandMentionByName(
163 "settings/automod"
164 )}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100165 )
166 .setEmoji("MOD.IMAGES.TOOSMALL")
167 .setStatus("Danger")
168 )
169 .setTitle("Content Scanning")
170 .setDescription("Content (NSFW, malware, scams) scanning")
171 .setPageId(4),
pineafan813bdf42022-07-24 10:39:10 +0100172 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100173 .setEmbed(
174 new EmojiEmbed()
175 .setTitle("Tickets")
176 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000177 "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 +0000178 `Tickets can be created by users with ${getCommandMentionByName(
179 "ticket/create"
180 )}, or by clicking a button created by moderators.\n` +
PineaFand471ccd2023-01-26 20:48:40 +0000181 `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 +0000182 `The category or channel to create threads in can be set with ${getCommandMentionByName(
183 "settings/tickets"
184 )}\n` +
185 `When the ticket is resolved, anyone can run ${getCommandMentionByName(
186 "ticket/close"
187 )} (or click the button) to close it.\n` +
TheCodedProff86ba092023-01-27 17:10:07 -0500188 `Running ${getCommandMentionByName("ticket/close")} again will delete the ticket.`
Skyler Grey75ea9172022-08-06 10:22:23 +0100189 )
190 .setEmoji("GUILD.TICKET.CLOSE")
191 .setStatus("Danger")
192 )
193 .setTitle("Tickets")
194 .setDescription("Ticket system")
195 .setPageId(5),
pineafan813bdf42022-07-24 10:39:10 +0100196 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100197 .setEmbed(
198 new EmojiEmbed()
199 .setTitle("Tags")
200 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000201 "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 +0000202 `Tags can be created with ${getCommandMentionByName(
203 "tags/create"
204 )}, and can be edited with ${getCommandMentionByName("tags/edit")}\n` +
205 `Tags can be deleted with ${getCommandMentionByName(
206 "tags/delete"
207 )}, and can be listed with ${getCommandMentionByName("tags/list")}\n` +
TheCodedProff86ba092023-01-27 17:10:07 -0500208 `To use a tag, you can type ${getCommandMentionByName("tag")}, followed by the tag to send`
Skyler Grey75ea9172022-08-06 10:22:23 +0100209 )
210 .setEmoji("PUNISH.NICKNAME.RED")
211 .setStatus("Danger")
212 )
213 .setTitle("Tags")
214 .setDescription("Tag system")
215 .setPageId(6),
pineafan813bdf42022-07-24 10:39:10 +0100216 new Embed()
Skyler Grey75ea9172022-08-06 10:22:23 +0100217 .setEmbed(
218 new EmojiEmbed()
219 .setTitle("Premium")
220 .setDescription(
PineaFand471ccd2023-01-26 20:48:40 +0000221 "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 +0000222 "**No currently free commands will become premium features.**\n" +
223 "Premium features include creating ticket transcripts and attachment logs.\n\n" +
224 "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 +0100225 )
TheCodedProf1c3ad3c2023-01-25 17:58:36 -0500226 .setEmoji("NUCLEUS.PREMIUM")
Skyler Grey75ea9172022-08-06 10:22:23 +0100227 .setStatus("Danger")
228 )
229 .setTitle("Premium")
230 .setDescription("Premium features")
231 .setPageId(7)
pineafan63fc5e22022-08-04 22:04:10 +0100232 ];
pineafan813bdf42022-07-24 10:39:10 +0100233
PineaFan0d06edc2023-01-17 22:10:31 +0000234 const publicFilter = async (component: MessageComponentInteraction) => {
PineaFane6ba7882023-01-18 20:41:16 +0000235 return (component.member as Discord.GuildMember).permissions.has("ManageGuild");
pineafan63fc5e22022-08-04 22:04:10 +0100236 };
pineafan813bdf42022-07-24 10:39:10 +0100237
238 let selectPaneOpen = false;
239
Skyler Greyf21323a2022-08-13 23:58:22 +0100240 let cancelled = false;
241 let timedOut = false;
242 while (!cancelled && !timedOut) {
PineaFane6ba7882023-01-18 20:41:16 +0000243 let selectPane: ActionRowBuilder<Discord.StringSelectMenuBuilder | ButtonBuilder>[] = [];
pineafan813bdf42022-07-24 10:39:10 +0100244
245 if (selectPaneOpen) {
PineaFane6ba7882023-01-18 20:41:16 +0000246 const options: Discord.StringSelectMenuOptionBuilder[] = [];
Skyler Grey75ea9172022-08-06 10:22:23 +0100247 pages.forEach((embed) => {
Skyler Greyda16adf2023-03-05 10:22:12 +0000248 options.push(
249 new Discord.StringSelectMenuOptionBuilder()
250 .setLabel(embed.title)
251 .setValue(embed.pageId.toString())
252 .setDescription(embed.description || "")
PineaFane6ba7882023-01-18 20:41:16 +0000253 );
pineafan63fc5e22022-08-04 22:04:10 +0100254 });
Skyler Grey75ea9172022-08-06 10:22:23 +0100255 selectPane = [
PineaFane6ba7882023-01-18 20:41:16 +0000256 new ActionRowBuilder<Discord.StringSelectMenuBuilder>().addComponents([
257 new Discord.StringSelectMenuBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100258 .addOptions(options)
259 .setCustomId("page")
260 .setMaxValues(1)
261 .setPlaceholder("Choose a page...")
262 ])
263 ];
pineafan813bdf42022-07-24 10:39:10 +0100264 }
PineaFane6ba7882023-01-18 20:41:16 +0000265 const components: ActionRowBuilder<ButtonBuilder | Discord.StringSelectMenuBuilder>[] = selectPane.concat([
266 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProf21c08592022-09-13 14:14:43 -0400267 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100268 .setCustomId("left")
269 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400270 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100271 .setDisabled(page === 0),
TheCodedProf21c08592022-09-13 14:14:43 -0400272 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100273 .setCustomId("select")
274 .setEmoji(getEmojiByName("CONTROL.MENU", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400275 .setStyle(selectPaneOpen ? ButtonStyle.Primary : ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100276 .setDisabled(false),
TheCodedProf21c08592022-09-13 14:14:43 -0400277 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100278 .setCustomId("right")
279 .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
TheCodedProf21c08592022-09-13 14:14:43 -0400280 .setStyle(ButtonStyle.Secondary)
Skyler Grey75ea9172022-08-06 10:22:23 +0100281 .setDisabled(page === pages.length - 1)
PineaFane6ba7882023-01-18 20:41:16 +0000282 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100283 ]);
pineafan813bdf42022-07-24 10:39:10 +0100284 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400285 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000286 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan813bdf42022-07-24 10:39:10 +0100287 await interaction.editReply({
288 embeds: [em],
289 components: components
290 });
291 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400292 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000293 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
pineafan3a02ea32022-08-11 21:35:04 +0100294 (await m.edit({
pineafan813bdf42022-07-24 10:39:10 +0100295 embeds: [em],
pineafan3a02ea32022-08-11 21:35:04 +0100296 components: components
297 })) as Message;
pineafan813bdf42022-07-24 10:39:10 +0100298 }
pineafan63fc5e22022-08-04 22:04:10 +0100299 let i;
pineafan813bdf42022-07-24 10:39:10 +0100300 try {
Skyler Grey75ea9172022-08-06 10:22:23 +0100301 i = await m.awaitMessageComponent({
302 filter: interaction
Skyler Greyda16adf2023-03-05 10:22:12 +0000303 ? (i) => {
304 return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id;
305 }
PineaFan0d06edc2023-01-17 22:10:31 +0000306 : publicFilter,
Skyler Grey75ea9172022-08-06 10:22:23 +0100307 time: 300000
308 });
309 } catch (e) {
Skyler Greyf21323a2022-08-13 23:58:22 +0100310 timedOut = true;
311 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100312 }
TheCodedProf267563a2023-01-21 17:00:57 -0500313 await i.deferUpdate();
pineafan3a02ea32022-08-11 21:35:04 +0100314 if (!("customId" in i.component)) {
315 continue;
316 } else if (i.component.customId === "left") {
pineafan813bdf42022-07-24 10:39:10 +0100317 if (page > 0) page--;
318 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100319 } else if (i.component.customId === "right") {
pineafan813bdf42022-07-24 10:39:10 +0100320 if (page < pages.length - 1) page++;
321 selectPaneOpen = false;
pineafane23c4ec2022-07-27 21:56:27 +0100322 } else if (i.component.customId === "select") {
pineafan813bdf42022-07-24 10:39:10 +0100323 selectPaneOpen = !selectPaneOpen;
TheCodedProf4a6d5712023-01-19 15:54:40 -0500324 } else if (i.isStringSelectMenu() && i.component.customId === "page") {
325 page = parseInt(i.values[0]!);
pineafan813bdf42022-07-24 10:39:10 +0100326 selectPaneOpen = false;
327 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100328 cancelled = true;
pineafan813bdf42022-07-24 10:39:10 +0100329 }
330 }
Skyler Greyf21323a2022-08-13 23:58:22 +0100331 if (timedOut) {
332 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400333 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000334 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100335 text: "Message timed out"
336 });
337 await interaction.editReply({
338 embeds: [em],
339 components: []
340 });
341 } else {
TheCodedProf21c08592022-09-13 14:14:43 -0400342 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000343 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page)).setFooter({
Skyler Greyf21323a2022-08-13 23:58:22 +0100344 text: "Message timed out"
345 });
346 await m.edit({
347 embeds: [em],
348 components: []
349 });
350 }
pineafan813bdf42022-07-24 10:39:10 +0100351 } else {
Skyler Greyf21323a2022-08-13 23:58:22 +0100352 if (interaction) {
TheCodedProf21c08592022-09-13 14:14:43 -0400353 const em = new Discord.EmbedBuilder(pages[page]!.embed);
PineaFane6ba7882023-01-18 20:41:16 +0000354 em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
Skyler Greyf21323a2022-08-13 23:58:22 +0100355 em.setFooter({ text: "Message closed" });
Skyler Greyf4f21c42023-03-08 14:36:29 +0000356 await interaction.editReply({
Skyler Greyf21323a2022-08-13 23:58:22 +0100357 embeds: [em],
358 components: []
359 });
360 } else {
Skyler Greyf4f21c42023-03-08 14:36:29 +0000361 await m.delete();
Skyler Greyf21323a2022-08-13 23:58:22 +0100362 }
pineafan813bdf42022-07-24 10:39:10 +0100363 }
pineafan63fc5e22022-08-04 22:04:10 +0100364};