blob: d410da8fcd94214f7c9ca1dfbffd0a8161a5ea15 [file] [log] [blame]
pineafan1e462ab2023-03-07 21:34:06 +00001import {
2 ActionRowBuilder,
3 AttachmentBuilder,
4 ButtonBuilder,
5 ButtonInteraction,
6 ButtonStyle,
7 ChannelType,
8 CommandInteraction,
9 ComponentType,
10 Guild,
TheCodedProfa38cbb32023-03-11 17:22:25 -050011 GuildTextBasedChannel,
pineafan1e462ab2023-03-07 21:34:06 +000012 ModalBuilder,
13 ModalSubmitInteraction,
14 TextInputBuilder,
15 TextInputStyle
16} from "discord.js";
TheCodedProff86ba092023-01-27 17:10:07 -050017import type { SlashCommandSubcommandBuilder } from "discord.js";
pineafan4edb7762022-06-26 19:21:04 +010018import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
pineafan63fc5e22022-08-04 22:04:10 +010019import client from "../../utils/client.js";
TheCodedProfe92b9b52023-03-06 17:07:34 -050020import config from "../../config/main.js";
pineafan4f164f32022-02-26 22:07:12 +000021
22const command = (builder: SlashCommandSubcommandBuilder) =>
Skyler Grey75ea9172022-08-06 10:22:23 +010023 builder.setName("stats").setDescription("Gets the bot's stats");
pineafan4f164f32022-02-26 22:07:12 +000024
Skyler Greyb9616ec2023-03-15 00:22:12 +000025const confirm = async (interaction: ButtonInteraction) => {
TheCodedProf35e73712023-03-10 17:35:35 -050026 const requiredTexts = [
27 "just do it",
28 "yes, do as i say!",
29 "clicksminuteper/nucleus",
30 "i've said it once i'll say it again",
31 "no, i've changed my mind",
32 "this incident will be reported",
33 "coded told me to",
34 "mini told me to",
35 "pinea told me to",
36 "what's a java script",
37 "it's a feature not a bug",
38 "that never happened during testing"
TheCodedProfca29ebb2023-03-10 17:40:09 -050039 ];
TheCodedProf35e73712023-03-10 17:35:35 -050040 const chosen = requiredTexts[Math.floor(Math.random() * (requiredTexts.length - 1))]!;
41
42 const modal = new ModalBuilder()
TheCodedProfca29ebb2023-03-10 17:40:09 -050043 .addComponents(
44 new ActionRowBuilder<TextInputBuilder>().addComponents(
45 new TextInputBuilder()
46 .setStyle(TextInputStyle.Short)
47 .setLabel(`Type "${chosen}" below`)
48 .setCustomId("confirm")
PineappleFandc85ab42023-03-24 17:19:17 +000049 .setPlaceholder("1234567890")
TheCodedProfca29ebb2023-03-10 17:40:09 -050050 .setMinLength(chosen.length)
51 .setMaxLength(chosen.length)
TheCodedProf35e73712023-03-10 17:35:35 -050052 )
TheCodedProfca29ebb2023-03-10 17:40:09 -050053 )
54 .setTitle("Admin Panel")
55 .setCustomId("adminPanel");
TheCodedProf35e73712023-03-10 17:35:35 -050056 await interaction.showModal(modal);
57 let out: ModalSubmitInteraction;
58 try {
59 out = await interaction.awaitModalSubmit({
60 filter: (i) => i.customId === "adminPanel" && i.user.id === interaction.user.id,
61 time: 300000
62 });
63 } catch {
64 return;
65 }
66 await out.deferUpdate();
67 const typed = out.fields.getTextInputValue("confirm");
TheCodedProfca29ebb2023-03-10 17:40:09 -050068 return typed.toLowerCase() === chosen.toLowerCase();
69};
TheCodedProf35e73712023-03-10 17:35:35 -050070
pineafanbd02b4a2022-08-05 22:01:38 +010071const callback = async (interaction: CommandInteraction): Promise<void> => {
pineafan1e462ab2023-03-07 21:34:06 +000072 const description = `**Servers:** ${client.guilds.cache.size}\n` + `**Ping:** \`${client.ws.ping * 2}ms\``;
TheCodedProfe92b9b52023-03-06 17:07:34 -050073 const m = await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +010074 embeds: [
75 new EmojiEmbed()
76 .setTitle("Stats")
TheCodedProfe92b9b52023-03-06 17:07:34 -050077 .setDescription(description)
Skyler Grey75ea9172022-08-06 10:22:23 +010078 .setStatus("Success")
TheCodedProf4a6d5712023-01-19 15:54:40 -050079 .setEmoji("SETTINGS.STATS.GREEN")
Skyler Grey75ea9172022-08-06 10:22:23 +010080 ],
TheCodedProfe92b9b52023-03-06 17:07:34 -050081 ephemeral: true,
82 fetchReply: true
pineafan377794f2022-04-18 19:01:01 +010083 });
TheCodedProfe92b9b52023-03-06 17:07:34 -050084 if (config.owners.includes(interaction.user.id)) {
Skyler Greyf4f21c42023-03-08 14:36:29 +000085 await interaction.editReply({
TheCodedProfe92b9b52023-03-06 17:07:34 -050086 embeds: [
87 new EmojiEmbed()
88 .setTitle("Admin")
89 .setDescription(description)
90 .setStatus("Success")
91 .setEmoji("SETTINGS.STATS.GREEN")
pineafan1e462ab2023-03-07 21:34:06 +000092 ],
93 components: [
94 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProfa38cbb32023-03-11 17:22:25 -050095 new ButtonBuilder().setCustomId("admin").setLabel("Admin Panel").setStyle(ButtonStyle.Primary),
TheCodedProf528de572023-03-11 17:28:29 -050096 new ButtonBuilder()
97 .setCustomId("announce")
98 .setLabel("Announce to all Guilds")
99 .setStyle(ButtonStyle.Danger)
pineafan1e462ab2023-03-07 21:34:06 +0000100 )
101 ]
TheCodedProfe92b9b52023-03-06 17:07:34 -0500102 });
103
104 const modal = new ModalBuilder()
105 .addComponents(
pineafan1e462ab2023-03-07 21:34:06 +0000106 new ActionRowBuilder<TextInputBuilder>().addComponents(
107 new TextInputBuilder()
108 .setStyle(TextInputStyle.Short)
109 .setLabel("Guild ID")
110 .setCustomId("guildID")
111 .setPlaceholder("Guild ID")
112 .setMinLength(16)
113 .setMaxLength(25)
114 )
TheCodedProfe92b9b52023-03-06 17:07:34 -0500115 )
116 .setTitle("Admin Panel")
pineafan1e462ab2023-03-07 21:34:06 +0000117 .setCustomId("adminPanel");
TheCodedProfe92b9b52023-03-06 17:07:34 -0500118 let i1: ButtonInteraction;
pineafan1e462ab2023-03-07 21:34:06 +0000119 const channel = await client.channels.fetch(interaction.channelId);
120 if (
121 !channel ||
122 [ChannelType.GuildCategory, ChannelType.GroupDM, ChannelType.GuildStageVoice].includes(channel.type)
123 )
124 return;
TheCodedProfe92b9b52023-03-06 17:07:34 -0500125 // console.log(interaction)
126 if (!("awaitMessageComponent" in channel)) return;
TheCodedProf35e73712023-03-10 17:35:35 -0500127 let GuildID = interaction.guildId;
TheCodedProfe92b9b52023-03-06 17:07:34 -0500128 try {
TheCodedProfa38cbb32023-03-11 17:22:25 -0500129 i1 = await m.awaitMessageComponent<ComponentType.Button>({
130 filter: (i) => i.user.id === interaction.user.id,
TheCodedProfe92b9b52023-03-06 17:07:34 -0500131 time: 300000
pineafan1e462ab2023-03-07 21:34:06 +0000132 });
TheCodedProfa38cbb32023-03-11 17:22:25 -0500133 } catch (e) {
134 console.log(e);
pineafan1e462ab2023-03-07 21:34:06 +0000135 return;
136 }
TheCodedProf528de572023-03-11 17:28:29 -0500137 switch (i1.customId) {
TheCodedProfa38cbb32023-03-11 17:22:25 -0500138 case "admin": {
139 if (!GuildID) {
140 await i1.showModal(modal);
141 let out: ModalSubmitInteraction;
142 try {
143 out = await i1.awaitModalSubmit({
144 filter: (i) => i.customId === "adminPanel" && i.user.id === interaction.user.id,
145 time: 300000
146 });
147 } catch {
148 return;
149 }
150 await out.deferUpdate();
151 GuildID = out.fields.getTextInputValue("guildID");
152 } else if (!client.guilds.cache.has(GuildID)) {
153 await interaction.editReply({
TheCodedProf528de572023-03-11 17:28:29 -0500154 embeds: [
155 new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")
156 ],
TheCodedProfa38cbb32023-03-11 17:22:25 -0500157 components: []
158 });
159 }
160
161 await interaction.editReply({
162 embeds: [],
163 components: [
164 new ActionRowBuilder<ButtonBuilder>().addComponents(
165 new ButtonBuilder().setCustomId("stats").setLabel("Stats").setStyle(ButtonStyle.Primary),
TheCodedProf528de572023-03-11 17:28:29 -0500166 new ButtonBuilder()
167 .setCustomId("data")
168 .setLabel("Guild data")
169 .setStyle(ButtonStyle.Secondary),
170 new ButtonBuilder()
171 .setCustomId("cache")
172 .setLabel("Reset cache")
173 .setStyle(ButtonStyle.Success),
TheCodedProfa38cbb32023-03-11 17:22:25 -0500174 new ButtonBuilder().setCustomId("leave").setLabel("Leave").setStyle(ButtonStyle.Danger),
TheCodedProf528de572023-03-11 17:28:29 -0500175 new ButtonBuilder()
176 .setCustomId("purge")
177 .setLabel("Delete data")
178 .setStyle(ButtonStyle.Danger)
TheCodedProfe92b9b52023-03-06 17:07:34 -0500179 )
TheCodedProfa38cbb32023-03-11 17:22:25 -0500180 ]
TheCodedProfca29ebb2023-03-10 17:40:09 -0500181 });
TheCodedProfa38cbb32023-03-11 17:22:25 -0500182 let i;
183 try {
184 i = await m.awaitMessageComponent<ComponentType.Button>({
185 filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
186 time: 300000
187 });
188 } catch {
189 return;
190 }
191 const guild = (await client.guilds.fetch(GuildID)) as Guild | null;
192 if (!guild) {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000193 await i.deferUpdate();
TheCodedProfa38cbb32023-03-11 17:22:25 -0500194 await interaction.editReply({
TheCodedProf528de572023-03-11 17:28:29 -0500195 embeds: [
196 new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")
197 ],
TheCodedProfa38cbb32023-03-11 17:22:25 -0500198 components: []
199 });
200 return;
201 }
202 if (i.customId === "stats") {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000203 await i.deferUpdate();
TheCodedProfa38cbb32023-03-11 17:22:25 -0500204 await interaction.editReply({
205 embeds: [
206 new EmojiEmbed()
207 .setTitle("Stats")
208 .setDescription(
209 `**Name:** ${guild.name}\n` +
210 `**ID:** \`${guild.id}\`\n` +
211 `**Owner:** ${client.users.cache.get(guild.ownerId)!.tag}\n` +
212 `**Member Count:** ${guild.memberCount}\n` +
213 `**Created:** <t:${guild.createdTimestamp}:F>\n` +
214 `**Added Nucleus:** <t:${guild.members.me!.joinedTimestamp}:R>\n` +
215 `**Nucleus' Perms:** https://discordapi.com/permissions.html#${guild.members.me!.permissions.valueOf()}\n`
216 )
217 .setStatus("Success")
218 .setEmoji("SETTINGS.STATS.GREEN")
219 ]
220 });
221 } else if (i.customId === "leave") {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000222 if (!(await confirm(i))) {
TheCodedProfa38cbb32023-03-11 17:22:25 -0500223 await interaction.editReply({
224 embeds: [new EmojiEmbed().setTitle("No changes were made").setStatus("Danger")],
225 components: []
226 });
227 return;
228 }
229 await guild.leave();
230 await interaction.editReply({
231 embeds: [
232 new EmojiEmbed()
233 .setTitle("Left")
234 .setDescription(`Left ${guild.name}`)
235 .setStatus("Success")
236 .setEmoji("SETTINGS.STATS.GREEN")
237 ],
238 components: []
239 });
240 } else if (i.customId === "data") {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000241 await i.deferUpdate();
TheCodedProfa38cbb32023-03-11 17:22:25 -0500242 // Get all the data and convert to a string
243 const data = await client.database.guilds.read(guild.id);
244 const stringified = JSON.stringify(data, null, 2);
245 const buffer = Buffer.from(stringified);
246 const attachment = new AttachmentBuilder(buffer).setName("data.json");
247 await interaction.editReply({
248 embeds: [
TheCodedProf528de572023-03-11 17:28:29 -0500249 new EmojiEmbed()
250 .setTitle("Data")
251 .setDescription(`Data for ${guild.name}`)
252 .setStatus("Success")
TheCodedProfa38cbb32023-03-11 17:22:25 -0500253 ],
254 components: [],
255 files: [attachment]
256 });
257 } else if (i.customId === "purge") {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000258 if (!(await confirm(i))) {
TheCodedProfa38cbb32023-03-11 17:22:25 -0500259 await interaction.editReply({
260 embeds: [new EmojiEmbed().setTitle("No changes were made").setStatus("Danger")],
261 components: []
262 });
263 return;
264 }
265 await client.database.guilds.delete(GuildID);
266 await client.database.history.delete(GuildID);
267 await client.database.notes.delete(GuildID);
268 await client.database.transcripts.deleteAll(GuildID);
269 await interaction.editReply({
270 embeds: [
271 new EmojiEmbed()
272 .setTitle("Purge")
273 .setDescription(`Deleted data for ${guild.name}`)
274 .setStatus("Success")
275 .setEmoji("SETTINGS.STATS.GREEN")
276 ],
277 components: []
278 });
279 } else if (i.customId === "cache") {
Skyler Greyb9616ec2023-03-15 00:22:12 +0000280 await i.deferUpdate();
TheCodedProfa38cbb32023-03-11 17:22:25 -0500281 await client.memory.forceUpdate(guild.id);
282 await interaction.editReply({
283 embeds: [
284 new EmojiEmbed()
285 .setTitle("Cache")
286 .setDescription(`Reset cache for ${guild.name}`)
287 .setStatus("Success")
288 .setEmoji("SETTINGS.STATS.GREEN")
289 ],
290 components: []
291 });
292 }
293 break;
TheCodedProfca29ebb2023-03-10 17:40:09 -0500294 }
TheCodedProfa38cbb32023-03-11 17:22:25 -0500295 case "announce": {
TheCodedProf528de572023-03-11 17:28:29 -0500296 const channelsToNotify = await client.database.guilds.staffChannels();
TheCodedProfa38cbb32023-03-11 17:22:25 -0500297 const modal2 = new ModalBuilder()
298 .addComponents(
299 new ActionRowBuilder<TextInputBuilder>().addComponents(
300 new TextInputBuilder()
301 .setStyle(TextInputStyle.Paragraph)
302 .setLabel("Announcement")
303 .setCustomId("announcement")
304 .setPlaceholder("Announcement...")
305 )
306 )
307 .setTitle("Announcement")
308 .setCustomId("announce");
309 await i1.showModal(modal2);
310 let out: ModalSubmitInteraction;
311 try {
312 out = await i1.awaitModalSubmit({
313 filter: (i) => i.customId === "announce" && i.user.id === interaction.user.id,
314 time: 300000
315 });
316 } catch {
317 return;
318 }
319 await out.deferUpdate();
320 const announcement = out.fields.getTextInputValue("announcement");
TheCodedProfca29ebb2023-03-10 17:40:09 -0500321 await interaction.editReply({
TheCodedProfa38cbb32023-03-11 17:22:25 -0500322 embeds: [
323 new EmojiEmbed()
324 .setTitle("Announcement")
TheCodedProf528de572023-03-11 17:28:29 -0500325 .setDescription(
326 `Announcement will be sent to ${channelsToNotify.length} channels.\n\n${announcement}`
327 )
TheCodedProfa38cbb32023-03-11 17:22:25 -0500328 .setStatus("Success")
329 .setEmoji("SETTINGS.STATS.GREEN")
330 ],
331 components: [
332 new ActionRowBuilder<ButtonBuilder>().addComponents(
TheCodedProf528de572023-03-11 17:28:29 -0500333 new ButtonBuilder()
334 .setCustomId("confirm")
335 .setLabel("Confirm")
336 .setStyle(ButtonStyle.Success),
TheCodedProfa38cbb32023-03-11 17:22:25 -0500337 new ButtonBuilder().setCustomId("cancel").setLabel("Cancel").setStyle(ButtonStyle.Danger)
338 )
339 ]
TheCodedProf35e73712023-03-10 17:35:35 -0500340 });
TheCodedProfa38cbb32023-03-11 17:22:25 -0500341
342 let i;
343 try {
344 i = await m.awaitMessageComponent<ComponentType.Button>({
345 filter: (i) => i.user.id === interaction.user.id,
346 time: 300000
347 });
348 } catch {
349 return;
350 }
351 if (i.customId === "confirm") {
352 await i.deferUpdate();
353 await interaction.editReply({
354 embeds: [
355 new EmojiEmbed()
356 .setTitle("Announcement")
TheCodedProf528de572023-03-11 17:28:29 -0500357 .setDescription(
358 `Sending to ${channelsToNotify.length} channels. Preview:\n\n${announcement}`
359 )
TheCodedProfa38cbb32023-03-11 17:22:25 -0500360 .setStatus("Success")
361 .setEmoji("SETTINGS.STATS.GREEN")
362 ],
363 components: []
364 });
365 const announcementEmbed = new EmojiEmbed()
366 .setTitle("Developer Announcement")
367 .setDescription(announcement)
368 .setStatus("Danger")
369 .setEmoji("NUCLEUS.LOGO")
TheCodedProf528de572023-03-11 17:28:29 -0500370 .setFooter({
371 text: `Sent by ${interaction.user.username}`,
372 iconURL: interaction.user.displayAvatarURL()
373 });
TheCodedProfa38cbb32023-03-11 17:22:25 -0500374 for (const channel of channelsToNotify) {
TheCodedProf528de572023-03-11 17:28:29 -0500375 const ch = (await client.channels.fetch(channel)) as GuildTextBasedChannel | null;
TheCodedProfa38cbb32023-03-11 17:22:25 -0500376 if (!ch) continue;
377 await ch.send({
378 embeds: [announcementEmbed]
379 });
380 }
381 await interaction.editReply({
382 embeds: [
383 new EmojiEmbed()
384 .setTitle("Announcement")
TheCodedProf528de572023-03-11 17:28:29 -0500385 .setDescription(
386 `Sent to ${channelsToNotify.length} channels. Preview:\n\n${announcement}`
387 )
TheCodedProfa38cbb32023-03-11 17:22:25 -0500388 .setStatus("Success")
389 .setEmoji("SETTINGS.STATS.GREEN")
390 ],
391 components: []
TheCodedProf528de572023-03-11 17:28:29 -0500392 });
TheCodedProfa38cbb32023-03-11 17:22:25 -0500393 } else if (i.customId === "cancel") {
394 await i.deferUpdate();
395 await interaction.editReply({
396 embeds: [new EmojiEmbed().setTitle("Announcement Cancelled").setStatus("Danger")],
397 components: []
398 });
399 }
400 break;
TheCodedProfca29ebb2023-03-10 17:40:09 -0500401 }
TheCodedProfe92b9b52023-03-06 17:07:34 -0500402 }
403 }
pineafan63fc5e22022-08-04 22:04:10 +0100404};
pineafan4f164f32022-02-26 22:07:12 +0000405
pineafan4f164f32022-02-26 22:07:12 +0000406export { command };
407export { callback };