blob: 7e524587b6ceca3c8d449c884cd02f81184febc4 [file] [log] [blame]
Skyler Greyda16adf2023-03-05 10:22:12 +00001import { getCommandMentionByName } from "../../utils/getCommandDataByName.js";
2import Discord, {
3 ActionRowBuilder,
4 ButtonBuilder,
5 ButtonInteraction,
6 PrivateThreadChannel,
7 TextChannel,
8 ButtonStyle,
9 CategoryChannel
10} from "discord.js";
pineafan813bdf42022-07-24 10:39:10 +010011import client from "../../utils/client.js";
12import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
13import getEmojiByName from "../../utils/getEmojiByName.js";
Skyler Greyda16adf2023-03-05 10:22:12 +000014import { preloadPage } from "../../utils/createTemporaryStorage.js";
15import { LoadingEmbed } from "../../utils/defaults.js";
pineafan813bdf42022-07-24 10:39:10 +010016
PineaFan538d3752023-01-12 21:48:23 +000017export default async function (interaction: Discord.CommandInteraction | ButtonInteraction) {
PineaFana00db1b2023-01-02 15:32:54 +000018 if (!interaction.guild) return;
PineaFan0d06edc2023-01-17 22:10:31 +000019 const config = await client.database.guilds.read(interaction.guild.id);
Skyler Grey11236ba2022-08-08 21:13:33 +010020 const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
PineaFan0d06edc2023-01-17 22:10:31 +000021 const ticketChannel = config.tickets.category;
22 if (!("parent" in interaction.channel!)) {
23 return await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +010024 embeds: [
25 new EmojiEmbed()
PineaFan0d06edc2023-01-17 22:10:31 +000026 .setTitle("Not a ticket")
27 .setDescription("This channel isn't a ticket, so you can't delete it.")
Skyler Grey75ea9172022-08-06 10:22:23 +010028 .setStatus("Danger")
29 .setEmoji("CONTROL.BLOCKCROSS")
Skyler Greyda16adf2023-03-05 10:22:12 +000030 ],
31 ephemeral: true
Skyler Grey75ea9172022-08-06 10:22:23 +010032 });
PineaFan0d06edc2023-01-17 22:10:31 +000033 } else if (interaction.channel!.parent!.id !== ticketChannel) {
34 return await interaction.reply({
Skyler Grey75ea9172022-08-06 10:22:23 +010035 embeds: [
36 new EmojiEmbed()
PineaFan0d06edc2023-01-17 22:10:31 +000037 .setTitle("Not a ticket")
38 .setDescription("This channel isn't a ticket, so you can't delete it.")
Skyler Grey75ea9172022-08-06 10:22:23 +010039 .setStatus("Danger")
PineaFan0d06edc2023-01-17 22:10:31 +000040 .setEmoji("CONTROL.BLOCKCROSS")
Skyler Greyda16adf2023-03-05 10:22:12 +000041 ],
42 ephemeral: true
Skyler Grey75ea9172022-08-06 10:22:23 +010043 });
PineaFan0d06edc2023-01-17 22:10:31 +000044 }
45 const channel: PrivateThreadChannel | TextChannel = interaction.channel as PrivateThreadChannel | TextChannel;
Skyler Greyda16adf2023-03-05 10:22:12 +000046 let status: string | null = "topic" in interaction.channel ? interaction.channel!.topic : interaction.channel.name;
PineaFan0d06edc2023-01-17 22:10:31 +000047 status = status ?? "";
Skyler Greyda16adf2023-03-05 10:22:12 +000048 if (status.endsWith("Archived")) {
49 status = "Archived";
50 } else {
51 status = "Active";
52 }
PineaFan0d06edc2023-01-17 22:10:31 +000053
Skyler Greyda16adf2023-03-05 10:22:12 +000054 const uID =
55 channel.type === Discord.ChannelType.PrivateThread
56 ? channel.name.split(" - ")[1]
57 : channel.topic!.split(" ")[0];
PineaFan0d06edc2023-01-17 22:10:31 +000058
59 if (status === "Archived") {
60 // Delete the ticket
61
pineafan63fc5e22022-08-04 22:04:10 +010062 const data = {
Skyler Grey75ea9172022-08-06 10:22:23 +010063 meta: {
PineaFan0d06edc2023-01-17 22:10:31 +000064 type: "ticketClosed",
65 displayName: "Ticket Closed",
pineafan813bdf42022-07-24 10:39:10 +010066 calculateType: "ticketUpdate",
67 color: NucleusColors.red,
pineafan63fc5e22022-08-04 22:04:10 +010068 emoji: "GUILD.TICKET.CLOSE",
TheCodedProf6ec331b2023-02-20 12:13:06 -050069 timestamp: Date.now()
pineafan813bdf42022-07-24 10:39:10 +010070 },
71 list: {
Skyler Greyda16adf2023-03-05 10:22:12 +000072 ticketFor: entry(uID!, renderUser((await interaction.guild.members.fetch(uID!)).user)),
PineaFan0d06edc2023-01-17 22:10:31 +000073 closedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
TheCodedProf6ec331b2023-02-20 12:13:06 -050074 closed: entry(Date.now(), renderDelta(Date.now())),
PineaFan0d06edc2023-01-17 22:10:31 +000075 ticketChannel: entry(channel.id, channel.name)
pineafan813bdf42022-07-24 10:39:10 +010076 },
77 hidden: {
78 guild: interaction.guild.id
79 }
pineafan63fc5e22022-08-04 22:04:10 +010080 };
Skyler Greyf4f21c42023-03-08 14:36:29 +000081 await log(data);
PineaFan0d06edc2023-01-17 22:10:31 +000082
83 await channel.delete();
pineafane23c4ec2022-07-27 21:56:27 +010084 } else if (status === "Active") {
Skyler Greyda16adf2023-03-05 10:22:12 +000085 await interaction.reply({ embeds: LoadingEmbed, fetchReply: true });
TheCodedProf9c51a7e2023-02-27 17:11:13 -050086 // Archive the ticket
Skyler Greyda16adf2023-03-05 10:22:12 +000087 await interaction.channel.fetch();
PineaFan0d06edc2023-01-17 22:10:31 +000088 if (channel.isThread()) {
Skyler Greyf4f21c42023-03-08 14:36:29 +000089 await channel.setName(`${channel.name.replace("Active", "Archived")}`);
90 await channel.members.remove(channel.name.split(" - ")[1]!);
PineaFan0d06edc2023-01-17 22:10:31 +000091 } else {
Skyler Greyf4f21c42023-03-08 14:36:29 +000092 await channel.setTopic(`${(channel.topic ?? "").replace("Active", "Archived")}`);
Skyler Greyda16adf2023-03-05 10:22:12 +000093 if (!channel.topic!.includes("Archived")) {
Skyler Greyf4f21c42023-03-08 14:36:29 +000094 await channel.setTopic("0 Archived");
Skyler Greyda16adf2023-03-05 10:22:12 +000095 }
PineaFan0d06edc2023-01-17 22:10:31 +000096 await channel.permissionOverwrites.delete(channel.topic!.split(" ")[0]!);
97 }
Skyler Greyda16adf2023-03-05 10:22:12 +000098 preloadPage(interaction.channel.id, "privacy", "2");
TheCodedProf9c51a7e2023-02-27 17:11:13 -050099 const hasPremium = await client.database.premium.hasPremium(interaction.guild.id);
100 await interaction.editReply({
Skyler Grey75ea9172022-08-06 10:22:23 +0100101 embeds: [
102 new EmojiEmbed()
PineaFan0d06edc2023-01-17 22:10:31 +0000103 .setTitle("Archived Ticket")
Skyler Greyda16adf2023-03-05 10:22:12 +0000104 .setDescription(
105 `This ticket has been Archived. Type ${getCommandMentionByName(
106 "ticket/close"
107 )} to delete it.\n` + hasPremium
108 ? "Creating a transcript will delete all messages in this ticket" +
109 `\n\nFor more info on transcripts, check ${getCommandMentionByName("privacy")}`
110 : ""
111 )
Skyler Grey75ea9172022-08-06 10:22:23 +0100112 .setStatus("Warning")
113 .setEmoji("GUILD.TICKET.ARCHIVED")
114 ],
115 components: [
PineaFan0d06edc2023-01-17 22:10:31 +0000116 new ActionRowBuilder<ButtonBuilder>().addComponents(
Skyler Grey75ea9172022-08-06 10:22:23 +0100117 [
TheCodedProf21c08592022-09-13 14:14:43 -0400118 new ButtonBuilder()
Skyler Grey75ea9172022-08-06 10:22:23 +0100119 .setLabel("Delete")
TheCodedProf21c08592022-09-13 14:14:43 -0400120 .setStyle(ButtonStyle.Danger)
Skyler Grey75ea9172022-08-06 10:22:23 +0100121 .setCustomId("closeticket")
122 .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
123 ].concat(
TheCodedProf9c51a7e2023-02-27 17:11:13 -0500124 hasPremium
Skyler Grey75ea9172022-08-06 10:22:23 +0100125 ? [
Skyler Greyda16adf2023-03-05 10:22:12 +0000126 new ButtonBuilder()
127 .setLabel("Create Transcript and Delete")
128 .setStyle(ButtonStyle.Primary)
129 .setCustomId("createtranscript")
130 .setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
131 ]
Skyler Grey75ea9172022-08-06 10:22:23 +0100132 : []
133 )
134 )
135 ]
136 });
PineaFan0d06edc2023-01-17 22:10:31 +0000137 const data = {
138 meta: {
139 type: "ticketClosed",
140 displayName: "Ticket Archived",
141 calculateType: "ticketUpdate",
142 color: NucleusColors.yellow,
143 emoji: "GUILD.TICKET.ARCHIVED",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500144 timestamp: Date.now()
PineaFan0d06edc2023-01-17 22:10:31 +0000145 },
146 list: {
Skyler Greyda16adf2023-03-05 10:22:12 +0000147 ticketFor: entry(uID!, renderUser((await interaction.guild.members.fetch(uID!)).user)),
PineaFan0d06edc2023-01-17 22:10:31 +0000148 archivedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
TheCodedProf6ec331b2023-02-20 12:13:06 -0500149 archived: entry(Date.now(), renderDelta(Date.now())),
PineaFan0d06edc2023-01-17 22:10:31 +0000150 ticketChannel: entry(channel.id, renderChannel(channel))
151 },
152 hidden: {
153 guild: interaction.guild.id
154 }
155 };
Skyler Greyf4f21c42023-03-08 14:36:29 +0000156 await log(data);
pineafan813bdf42022-07-24 10:39:10 +0100157 }
PineaFan0d06edc2023-01-17 22:10:31 +0000158 return;
pineafan813bdf42022-07-24 10:39:10 +0100159}
160
PineaFan0d06edc2023-01-17 22:10:31 +0000161async function purgeByUser(member: string, guild: string) {
PineaFan9b2ac4d2023-01-18 14:41:07 +0000162 const config = await client.database.guilds.read(guild);
PineaFan0d06edc2023-01-17 22:10:31 +0000163 const fetchedGuild = await client.guilds.fetch(guild);
pineafan813bdf42022-07-24 10:39:10 +0100164 if (!config.tickets.category) return;
Skyler Greyda16adf2023-03-05 10:22:12 +0000165 const tickets: CategoryChannel | TextChannel | undefined = fetchedGuild.channels.cache.get(
166 config.tickets.category
167 ) as CategoryChannel | TextChannel | undefined;
pineafan813bdf42022-07-24 10:39:10 +0100168 if (!tickets) return;
pineafan63fc5e22022-08-04 22:04:10 +0100169 let deleted = 0;
PineaFan9b2ac4d2023-01-18 14:41:07 +0000170 if (tickets.type === Discord.ChannelType.GuildCategory) {
171 // For channels, the topic is the user ID, then the word Active
172 const category = tickets as Discord.CategoryChannel;
Skyler Greyf4f21c42023-03-08 14:36:29 +0000173 for (const [_id, element] of category.children.cache) {
PineaFan9b2ac4d2023-01-18 14:41:07 +0000174 if (!(element.type === Discord.ChannelType.GuildText)) return;
Skyler Greyda16adf2023-03-05 10:22:12 +0000175 if (!((element as Discord.TextChannel).topic ?? "").includes(member)) return;
pineafan63fc5e22022-08-04 22:04:10 +0100176 try {
Skyler Greyf4f21c42023-03-08 14:36:29 +0000177 await element.delete();
PineaFan9b2ac4d2023-01-18 14:41:07 +0000178 deleted++;
179 } catch (e) {
180 console.error(e);
Skyler Grey75ea9172022-08-06 10:22:23 +0100181 }
Skyler Greyf4f21c42023-03-08 14:36:29 +0000182 };
PineaFan9b2ac4d2023-01-18 14:41:07 +0000183 } else {
184 // For threads, the name is the users name, id, then the word Active
185 const channel = tickets as Discord.TextChannel;
Skyler Greyf4f21c42023-03-08 14:36:29 +0000186 for (const [_id, element] of channel.threads.cache) {
PineaFan9b2ac4d2023-01-18 14:41:07 +0000187 if (!element.name.includes(member)) return;
188 try {
Skyler Greyf4f21c42023-03-08 14:36:29 +0000189 await element.delete();
PineaFan9b2ac4d2023-01-18 14:41:07 +0000190 deleted++;
191 } catch (e) {
192 console.error(e);
pineafan813bdf42022-07-24 10:39:10 +0100193 }
Skyler Greyf4f21c42023-03-08 14:36:29 +0000194 };
pineafan813bdf42022-07-24 10:39:10 +0100195 }
Skyler Greyda16adf2023-03-05 10:22:12 +0000196 if (!deleted) return;
PineaFan9b2ac4d2023-01-18 14:41:07 +0000197 const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
198 const data = {
199 meta: {
200 type: "ticketPurge",
201 displayName: "Tickets Purged",
202 calculateType: "ticketUpdate",
203 color: NucleusColors.red,
204 emoji: "GUILD.TICKET.DELETE",
TheCodedProf6ec331b2023-02-20 12:13:06 -0500205 timestamp: Date.now()
PineaFan9b2ac4d2023-01-18 14:41:07 +0000206 },
207 list: {
208 ticketFor: entry(member, renderUser(member)),
209 deletedBy: entry(null, "Member left server"),
TheCodedProf6ec331b2023-02-20 12:13:06 -0500210 deleted: entry(Date.now(), renderDelta(Date.now())),
PineaFan9b2ac4d2023-01-18 14:41:07 +0000211 ticketsDeleted: deleted
212 },
213 hidden: {
214 guild: guild
215 }
216 };
Skyler Greyf4f21c42023-03-08 14:36:29 +0000217 await log(data);
pineafan813bdf42022-07-24 10:39:10 +0100218}
219
TheCodedProf9c51a7e2023-02-27 17:11:13 -0500220export { purgeByUser };