blob: bd83782176f9bfb068b63fd814ddf24674ad9b8c [file] [log] [blame]
PineaFan0d06edc2023-01-17 22:10:31 +00001import { LoadingEmbed } from "../../utils/defaults.js";
TheCodedProfafca98b2023-01-17 22:25:43 -05002import Discord, { CommandInteraction, Message, ActionRowBuilder, GuildMember, StringSelectMenuBuilder, StringSelectMenuInteraction, AutocompleteInteraction } from "discord.js";
pineafan0bc04162022-07-25 17:22:26 +01003import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
4import confirmationMessage from "../../utils/confirmationMessage.js";
TheCodedProfafca98b2023-01-17 22:25:43 -05005import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
pineafan0bc04162022-07-25 17:22:26 +01006import client from "../../utils/client.js";
pineafan63fc5e22022-08-04 22:04:10 +01007import convertCurlyBracketString from "../../utils/convertCurlyBracketString.js";
Skyler Grey75ea9172022-08-06 10:22:23 +01008import { callback as statsChannelAddCallback } from "../../reflex/statsChannelUpdate.js";
pineafan63fc5e22022-08-04 22:04:10 +01009import singleNotify from "../../utils/singleNotify.js";
pineafan708692b2022-07-24 22:16:22 +010010
11const command = (builder: SlashCommandSubcommandBuilder) =>
12 builder
pineafan63fc5e22022-08-04 22:04:10 +010013 .setName("stats")
Skyler Grey11236ba2022-08-08 21:13:33 +010014 .setDescription("Controls channels which update when someone joins or leaves the server")
15 .addChannelOption((option) => option.setName("channel").setDescription("The channel to modify"))
Skyler Grey75ea9172022-08-06 10:22:23 +010016 .addStringOption((option) =>
17 option
18 .setName("name")
Skyler Grey11236ba2022-08-08 21:13:33 +010019 .setDescription("The new channel name | Enter any text or use the extra variables like {memberCount}")
Skyler Grey75ea9172022-08-06 10:22:23 +010020 .setAutocomplete(true)
21 );
pineafan708692b2022-07-24 22:16:22 +010022
pineafan3a02ea32022-08-11 21:35:04 +010023const callback = async (interaction: CommandInteraction): Promise<unknown> => {
TheCodedProfafca98b2023-01-17 22:25:43 -050024 singleNotify("statsChannelDeleted", interaction.guild!.id, true);
Skyler Grey75ea9172022-08-06 10:22:23 +010025 const m = (await interaction.reply({
26 embeds: LoadingEmbed,
27 ephemeral: true,
28 fetchReply: true
29 })) as Message;
TheCodedProfafca98b2023-01-17 22:25:43 -050030 let config = await client.database.guilds.read(interaction.guild!.id);
31 if (interaction.options.get("name")?.value as string) {
pineafane23c4ec2022-07-27 21:56:27 +010032 let channel;
TheCodedProfafca98b2023-01-17 22:25:43 -050033 if (Object.keys(config["stats"]).length >= 25) {
Skyler Grey75ea9172022-08-06 10:22:23 +010034 return await interaction.editReply({
35 embeds: [
36 new EmojiEmbed()
37 .setEmoji("CHANNEL.TEXT.DELETE")
38 .setTitle("Stats Channel")
Skyler Grey11236ba2022-08-08 21:13:33 +010039 .setDescription("You can only have 25 stats channels in a server")
Skyler Grey75ea9172022-08-06 10:22:23 +010040 .setStatus("Danger")
41 ]
42 });
pineafane23c4ec2022-07-27 21:56:27 +010043 }
pineafan708692b2022-07-24 22:16:22 +010044 try {
TheCodedProfafca98b2023-01-17 22:25:43 -050045 channel = interaction.options.get("channel")?.channel as Discord.Channel;
pineafan708692b2022-07-24 22:16:22 +010046 } catch {
Skyler Grey75ea9172022-08-06 10:22:23 +010047 return await interaction.editReply({
48 embeds: [
49 new EmojiEmbed()
50 .setEmoji("CHANNEL.TEXT.DELETE")
51 .setTitle("Stats Channel")
Skyler Grey11236ba2022-08-08 21:13:33 +010052 .setDescription("The channel you provided is not a valid channel")
Skyler Grey75ea9172022-08-06 10:22:23 +010053 .setStatus("Danger")
54 ]
55 });
pineafan708692b2022-07-24 22:16:22 +010056 }
pineafan63fc5e22022-08-04 22:04:10 +010057 channel = channel as Discord.TextChannel;
TheCodedProfafca98b2023-01-17 22:25:43 -050058 if (channel.guild.id !== interaction.guild!.id) {
Skyler Grey75ea9172022-08-06 10:22:23 +010059 return interaction.editReply({
60 embeds: [
61 new EmojiEmbed()
62 .setTitle("Stats Channel")
Skyler Grey11236ba2022-08-08 21:13:33 +010063 .setDescription("You must choose a channel in this server")
Skyler Grey75ea9172022-08-06 10:22:23 +010064 .setStatus("Danger")
65 .setEmoji("CHANNEL.TEXT.DELETE")
66 ]
67 });
pineafan708692b2022-07-24 22:16:22 +010068 }
Skyler Grey75ea9172022-08-06 10:22:23 +010069 let newName = await convertCurlyBracketString(
TheCodedProfafca98b2023-01-17 22:25:43 -050070 interaction.options.get("name")?.value as string,
71 "",
72 "",
73 interaction.guild!.name,
74 interaction.guild!.members
Skyler Grey75ea9172022-08-06 10:22:23 +010075 );
TheCodedProfafca98b2023-01-17 22:25:43 -050076 if (interaction.options.get("channel")?.channel!.type === Discord.ChannelType.GuildText) {
pineafan63fc5e22022-08-04 22:04:10 +010077 newName = newName.toLowerCase().replace(/[\s]/g, "-");
pineafan708692b2022-07-24 22:16:22 +010078 }
pineafan63fc5e22022-08-04 22:04:10 +010079 const confirmation = await new confirmationMessage(interaction)
TheCodedProfafca98b2023-01-17 22:25:43 -050080 .setEmoji("CHANNEL.TEXT.EDIT")
pineafan708692b2022-07-24 22:16:22 +010081 .setTitle("Stats Channel")
Skyler Grey75ea9172022-08-06 10:22:23 +010082 .setDescription(
Skyler Grey11236ba2022-08-08 21:13:33 +010083 `Are you sure you want to set <#${channel.id}> to a stats channel?\n\n*Preview: ${newName.replace(
Skyler Grey75ea9172022-08-06 10:22:23 +010084 /^ +| $/g,
85 ""
86 )}*`
87 )
pineafan708692b2022-07-24 22:16:22 +010088 .setColor("Warning")
89 .setInverted(true)
TheCodedProfafca98b2023-01-17 22:25:43 -050090 .setFailedMessage(`Could not convert <#${channel.id}> to a stats chanel.`, "Danger", "CHANNEL.TEXT.DELETE")
pineafan63fc5e22022-08-04 22:04:10 +010091 .send(true);
92 if (confirmation.cancelled) return;
pineafan708692b2022-07-24 22:16:22 +010093 if (confirmation.success) {
94 try {
TheCodedProfafca98b2023-01-17 22:25:43 -050095 const name = interaction.options.get("name")?.value as string;
96 const channel = interaction.options.get("channel")?.channel as Discord.TextChannel;
97 await client.database.guilds.write(interaction.guild!.id, {
Skyler Grey75ea9172022-08-06 10:22:23 +010098 [`stats.${channel.id}`]: { name: name, enabled: true }
99 });
Skyler Grey11236ba2022-08-08 21:13:33 +0100100 const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger;
pineafan63fc5e22022-08-04 22:04:10 +0100101 const data = {
Skyler Grey75ea9172022-08-06 10:22:23 +0100102 meta: {
pineafan63fc5e22022-08-04 22:04:10 +0100103 type: "statsChannelUpdate",
104 displayName: "Stats Channel Updated",
105 calculateType: "nucleusSettingsUpdated",
106 color: NucleusColors.yellow,
107 emoji: "CHANNEL.TEXT.EDIT",
108 timestamp: new Date().getTime()
109 },
110 list: {
Skyler Grey11236ba2022-08-08 21:13:33 +0100111 memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
112 changedBy: entry(interaction.user.id, renderUser(interaction.user)),
pineafan63fc5e22022-08-04 22:04:10 +0100113 channel: entry(channel.id, renderChannel(channel)),
Skyler Grey75ea9172022-08-06 10:22:23 +0100114 name: entry(
TheCodedProfafca98b2023-01-17 22:25:43 -0500115 interaction.options.get("name")?.value as string,
116 `\`${interaction.options.get("name")?.value as string}\``
Skyler Grey75ea9172022-08-06 10:22:23 +0100117 )
pineafan63fc5e22022-08-04 22:04:10 +0100118 },
119 hidden: {
TheCodedProfafca98b2023-01-17 22:25:43 -0500120 guild: interaction.guild!.id
pineafan708692b2022-07-24 22:16:22 +0100121 }
pineafan63fc5e22022-08-04 22:04:10 +0100122 };
123 log(data);
pineafan708692b2022-07-24 22:16:22 +0100124 } catch (e) {
pineafan63fc5e22022-08-04 22:04:10 +0100125 console.log(e);
Skyler Grey75ea9172022-08-06 10:22:23 +0100126 return interaction.editReply({
127 embeds: [
128 new EmojiEmbed()
129 .setTitle("Stats Channel")
Skyler Grey11236ba2022-08-08 21:13:33 +0100130 .setDescription("Something went wrong and the stats channel could not be set")
Skyler Grey75ea9172022-08-06 10:22:23 +0100131 .setStatus("Danger")
132 .setEmoji("CHANNEL.TEXT.DELETE")
133 ],
134 components: []
135 });
pineafan708692b2022-07-24 22:16:22 +0100136 }
137 } else {
Skyler Grey75ea9172022-08-06 10:22:23 +0100138 return interaction.editReply({
139 embeds: [
140 new EmojiEmbed()
141 .setTitle("Stats Channel")
142 .setDescription("No changes were made")
143 .setStatus("Success")
144 .setEmoji("CHANNEL.TEXT.CREATE")
145 ],
146 components: []
147 });
pineafan708692b2022-07-24 22:16:22 +0100148 }
TheCodedProfafca98b2023-01-17 22:25:43 -0500149 await statsChannelAddCallback(client, interaction.member as GuildMember);
pineafan0bc04162022-07-25 17:22:26 +0100150 }
Skyler Greyad002172022-08-16 18:48:26 +0100151 let timedOut = false;
152 while (!timedOut) {
TheCodedProfafca98b2023-01-17 22:25:43 -0500153 config = await client.database.guilds.read(interaction.guild!.id);
154 const stats = config["stats"];
155 const selectMenu = new StringSelectMenuBuilder()
pineafan0bc04162022-07-25 17:22:26 +0100156 .setCustomId("remove")
157 .setMinValues(1)
pineafan63fc5e22022-08-04 22:04:10 +0100158 .setMaxValues(Math.max(1, Object.keys(stats).length));
Skyler Grey75ea9172022-08-06 10:22:23 +0100159 await interaction.editReply({
160 embeds: [
161 new EmojiEmbed()
162 .setTitle("Stats Channel")
163 .setDescription(
164 "The following channels update when someone joins or leaves the server. You can select a channel to remove it from the list."
165 )
166 .setStatus("Success")
167 .setEmoji("CHANNEL.TEXT.CREATE")
168 ],
169 components: [
TheCodedProfafca98b2023-01-17 22:25:43 -0500170 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
Skyler Grey75ea9172022-08-06 10:22:23 +0100171 Object.keys(stats).length
172 ? [
173 selectMenu
Skyler Grey11236ba2022-08-08 21:13:33 +0100174 .setPlaceholder("Select a stats channel to remove, stopping it updating")
Skyler Grey75ea9172022-08-06 10:22:23 +0100175 .addOptions(
176 Object.keys(stats).map((key) => ({
TheCodedProfafca98b2023-01-17 22:25:43 -0500177 label: interaction.guild!.channels.cache.get(key)!.name,
Skyler Grey75ea9172022-08-06 10:22:23 +0100178 value: key,
TheCodedProfafca98b2023-01-17 22:25:43 -0500179 description: `${stats[key]!.name}`
Skyler Grey75ea9172022-08-06 10:22:23 +0100180 }))
181 )
182 ]
183 : [
184 selectMenu
Skyler Grey11236ba2022-08-08 21:13:33 +0100185 .setPlaceholder("The server has no stats channels")
Skyler Grey75ea9172022-08-06 10:22:23 +0100186 .setDisabled(true)
187 .setOptions([
188 {
189 label: "*Placeholder*",
190 value: "placeholder",
191 description: "No stats channels"
192 }
193 ])
194 ]
195 )
196 ]
197 });
TheCodedProfafca98b2023-01-17 22:25:43 -0500198 let i: StringSelectMenuInteraction;
pineafan0bc04162022-07-25 17:22:26 +0100199 try {
PineaFan0d06edc2023-01-17 22:10:31 +0000200 i = await m.awaitMessageComponent({
201 time: 300000,
202 filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
TheCodedProfafca98b2023-01-17 22:25:43 -0500203 }) as StringSelectMenuInteraction;
Skyler Grey75ea9172022-08-06 10:22:23 +0100204 } catch (e) {
Skyler Greyad002172022-08-16 18:48:26 +0100205 timedOut = true;
206 continue;
Skyler Grey75ea9172022-08-06 10:22:23 +0100207 }
pineafan63fc5e22022-08-04 22:04:10 +0100208 i.deferUpdate();
pineafan0bc04162022-07-25 17:22:26 +0100209 if (i.customId === "remove") {
pineafan63fc5e22022-08-04 22:04:10 +0100210 const toRemove = i.values;
Skyler Grey75ea9172022-08-06 10:22:23 +0100211 await client.database.guilds.write(
TheCodedProfafca98b2023-01-17 22:25:43 -0500212 interaction.guild!.id,
Skyler Grey75ea9172022-08-06 10:22:23 +0100213 null,
214 toRemove.map((k) => `stats.${k}`)
215 );
pineafan0bc04162022-07-25 17:22:26 +0100216 }
pineafan708692b2022-07-24 22:16:22 +0100217 }
Skyler Grey75ea9172022-08-06 10:22:23 +0100218 await interaction.editReply({
TheCodedProfafca98b2023-01-17 22:25:43 -0500219 embeds: [new Discord.EmbedBuilder(m.embeds[0]!.data).setFooter({ text: "Message timed out" })],
Skyler Grey75ea9172022-08-06 10:22:23 +0100220 components: []
221 });
pineafan63fc5e22022-08-04 22:04:10 +0100222};
pineafan708692b2022-07-24 22:16:22 +0100223
PineaFan64486c42022-12-28 09:21:04 +0000224const check = (interaction: CommandInteraction) => {
Skyler Grey75ea9172022-08-06 10:22:23 +0100225 const member = interaction.member as Discord.GuildMember;
TheCodedProfafca98b2023-01-17 22:25:43 -0500226 if (!member.permissions.has("ManageChannels"))
PineaFan0d06edc2023-01-17 22:10:31 +0000227 return "You must have the *Manage Channels* permission to use this command";
pineafan708692b2022-07-24 22:16:22 +0100228 return true;
pineafan63fc5e22022-08-04 22:04:10 +0100229};
pineafan708692b2022-07-24 22:16:22 +0100230
PineaFan538d3752023-01-12 21:48:23 +0000231const autocomplete = async (interaction: AutocompleteInteraction): Promise<string[]> => {
232 if (!interaction.guild) return [];
233 const prompt = interaction.options.getString("tag");
234 // generateStatsChannelAutocomplete(int.options.getString("name") ?? "")
235 const results = generateStatsChannelAutocomplete(prompt ?? "");
236 return results;
237};
238
239
240
pineafan708692b2022-07-24 22:16:22 +0100241export { command };
242export { callback };
Skyler Grey75ea9172022-08-06 10:22:23 +0100243export { check };
PineaFan0d06edc2023-01-17 22:10:31 +0000244export { autocomplete };