blob: 7957b18027563b4d27c40888779b9c8b7f614277 [file] [log] [blame]
pineafan63fc5e22022-08-04 22:04:10 +01001import { callback as roleMenu } from "../actions/roleMenu.js";
pineafan73a7c4a2022-07-24 10:38:04 +01002import verify from "../reflex/verify.js";
3import create from "../actions/tickets/create.js";
4import close from "../actions/tickets/delete.js";
5import createTranscript from "../premium/createTranscript.js";
PineaFana34d04b2023-01-03 22:05:42 +00006
TheCodedProfca29ebb2023-03-10 17:40:09 -05007import {
8 ActionRowBuilder,
9 ButtonBuilder,
10 ButtonInteraction,
11 ButtonStyle,
12 Interaction,
13 InteractionEditReplyOptions,
14 ModalBuilder,
15 ModalSubmitInteraction,
16 TextInputBuilder,
17 TextInputStyle
18} from "discord.js";
PineaFan752af462022-12-31 21:59:38 +000019import type { NucleusClient } from "../utils/client.js";
PineaFan1dee28f2023-01-16 22:09:07 +000020import EmojiEmbed from "../utils/generateEmojiEmbed.js";
pineafanad54d752022-04-18 19:01:43 +010021
pineafan6de4da52023-03-07 20:43:44 +000022import { callback as banCallback, check as banCheck } from "../commands/mod/ban.js";
23import { callback as kickCallback, check as kickCheck } from "../commands/mod/kick.js";
24import { callback as muteCallback, check as muteCheck } from "../commands/mod/mute.js";
25import { callback as nicknameCallback, check as nicknameCheck } from "../commands/mod/nick.js";
26import { callback as warnCallback, check as warnCheck } from "../commands/mod/warn.js";
TheCodedProf4a7c25d2023-06-07 17:09:45 -040027import { callback as logDetailsCallback } from "../actions/logs/showDetails.js";
TheCodedProf35e73712023-03-10 17:35:35 -050028import client from "../utils/client.js";
pineafan6de4da52023-03-07 20:43:44 +000029
pineafan63fc5e22022-08-04 22:04:10 +010030export const event = "interactionCreate";
pineafanad54d752022-04-18 19:01:43 +010031
pineafan6de4da52023-03-07 20:43:44 +000032async function errorMessage(interaction: ButtonInteraction, message: string) {
33 await interaction.reply({
pineafan1e462ab2023-03-07 21:34:06 +000034 embeds: [new EmojiEmbed().setDescription(message).setStatus("Danger")],
pineafan6de4da52023-03-07 20:43:44 +000035 ephemeral: true,
36 components: []
37 });
38}
39
pineafan0f5cc782022-08-12 21:55:42 +010040async function interactionCreate(interaction: Interaction) {
PineaFana34d04b2023-01-03 22:05:42 +000041 if (interaction.isButton()) {
TheCodedProf35e73712023-03-10 17:35:35 -050042 if (interaction.customId.endsWith(":Suggestion")) {
TheCodedProfca29ebb2023-03-10 17:40:09 -050043 const value =
44 interaction.customId.startsWith("accept") || interaction.customId.startsWith("implement")
45 ? true
46 : false;
TheCodedProf35e73712023-03-10 17:35:35 -050047 return await modifySuggestion(interaction, value);
48 }
pineafan435a8782023-06-24 12:45:58 +010049 if (interaction.customId === "log:message.edit") {
50 await interaction.channel?.messages.fetch({ message: interaction.message.id, force: true });
51 const attachment = interaction.message.embeds[0]?.image ?? interaction.message.attachments.first();
TheCodedProfc3195b52023-06-23 15:53:00 -040052 if (!attachment) return;
pineafan435a8782023-06-24 12:45:58 +010053 const attachmentData = await (await fetch(attachment.url)).text();
pineafan67c9f1f2023-06-23 22:50:26 +010054 const decoded = atob(attachmentData);
pineafan435a8782023-06-24 12:45:58 +010055 const json = (
56 JSON.parse(decoded) as { data: { count: number; value: string; added?: boolean; removed?: boolean }[] }
57 ).data;
58 // "Before" is everything where added is false
59 // "After" is everything where removed is false
60 const before: string = json
61 .filter((d) => !d.added)
62 .map((d) => d.value)
63 .join("");
64 const after: string = json
65 .filter((d) => !d.removed)
66 .map((d) => d.value)
67 .join("");
68 const { renderDateFooter } = client.logger;
69 await interaction.reply({
70 embeds: [
71 new EmojiEmbed()
72 .setTitle("Before")
73 .setDescription(before)
74 .setStatus("Danger")
pineafan33a307e2023-06-24 18:29:47 +010075 .setEmoji("ICONS.OPP.ADD")
76 ],
77 ephemeral: true
78 });
79 await interaction.followUp({
80 embeds: [
pineafan435a8782023-06-24 12:45:58 +010081 new EmojiEmbed()
82 .setTitle("After")
83 .setDescription(after)
84 .setStatus("Success")
85 .setEmoji("ICONS.ADD")
86 .setFooter({ text: `Edited at ${renderDateFooter(interaction.message.createdTimestamp!)}` }) // Created timestamp of the log is when the edit was made
87 ],
88 ephemeral: true
89 });
90 } else if (interaction.customId === "log:message.delete") {
91 await interaction.channel?.messages.fetch({ message: interaction.message.id, force: true });
92 const attachment = interaction.message.embeds[0]?.image ?? interaction.message.attachments.first();
93 if (!attachment) return;
94 const attachmentData = await (await fetch(attachment.url)).text();
95 const decoded = atob(attachmentData);
96 const json = JSON.parse(decoded) as { data: string };
97 await interaction.reply({
98 embeds: [
99 new EmojiEmbed()
100 .setTitle("Message")
101 .setDescription(json.data)
102 .setStatus("Danger")
103 .setEmoji("MESSAGE.DELETE")
104 .setFooter({ text: `Deleted at ${client.logger.renderDateFooter(Date.now())}` })
105 ],
106 ephemeral: true
107 });
TheCodedProfc3195b52023-06-23 15:53:00 -0400108 }
PineaFan538d3752023-01-12 21:48:23 +0000109 switch (interaction.customId) {
Skyler Greyda16adf2023-03-05 10:22:12 +0000110 case "rolemenu": {
111 return await roleMenu(interaction);
112 }
113 case "verifybutton": {
114 return await verify(interaction);
115 }
116 case "createticket": {
117 return await create(interaction);
118 }
119 case "closeticket": {
120 return await close(interaction);
121 }
122 case "createtranscript": {
123 return await createTranscript(interaction);
124 }
TheCodedProf4a7c25d2023-06-07 17:09:45 -0400125 case "log:showDetails": {
126 return await logDetailsCallback(interaction);
127 }
pineafan02ba0232022-07-24 22:16:15 +0100128 }
pineafan6de4da52023-03-07 20:43:44 +0000129 // Mod actions
130 if (interaction.customId.startsWith("mod:")) {
131 const action = interaction.customId.split(":")[1];
132 const memberId = interaction.customId.split(":")[2];
133 const member = await interaction.guild?.members.fetch(memberId!);
134 switch (action) {
135 case "kick": {
TheCodedProf35e73712023-03-10 17:35:35 -0500136 const check = kickCheck(interaction, false, member);
pineafan6de4da52023-03-07 20:43:44 +0000137 if (check !== true) return await errorMessage(interaction, check!);
138 return await kickCallback(interaction, member);
pineafan1e462ab2023-03-07 21:34:06 +0000139 }
140 case "ban": {
TheCodedProf35e73712023-03-10 17:35:35 -0500141 const check = banCheck(interaction, false, member);
pineafan6de4da52023-03-07 20:43:44 +0000142 if (check !== true) return await errorMessage(interaction, check!);
143 return await banCallback(interaction, member);
pineafan1e462ab2023-03-07 21:34:06 +0000144 }
145 case "mute": {
TheCodedProf35e73712023-03-10 17:35:35 -0500146 const check = muteCheck(interaction, false, member);
pineafan6de4da52023-03-07 20:43:44 +0000147 if (check !== true) return await errorMessage(interaction, check!);
148 return await muteCallback(interaction, member);
pineafan1e462ab2023-03-07 21:34:06 +0000149 }
150 case "nickname": {
TheCodedProf35e73712023-03-10 17:35:35 -0500151 const check = nicknameCheck(interaction, false, member);
pineafan6de4da52023-03-07 20:43:44 +0000152 if (check !== true) return await errorMessage(interaction, check || "Something went wrong");
153 return await nicknameCallback(interaction, member);
pineafan1e462ab2023-03-07 21:34:06 +0000154 }
155 case "warn": {
TheCodedProf35e73712023-03-10 17:35:35 -0500156 const check = warnCheck(interaction, false, member);
pineafan6de4da52023-03-07 20:43:44 +0000157 if (check !== true) return await errorMessage(interaction, check!);
158 return await warnCallback(interaction, member);
159 }
160 }
161 }
pineafanad54d752022-04-18 19:01:43 +0100162 }
163}
164
TheCodedProf35e73712023-03-10 17:35:35 -0500165const getReason = async (buttonInteraction: ButtonInteraction, prompt: string) => {
166 const modal = new ModalBuilder()
167 .addComponents(
168 new ActionRowBuilder<TextInputBuilder>().addComponents(
TheCodedProfca29ebb2023-03-10 17:40:09 -0500169 new TextInputBuilder().setStyle(TextInputStyle.Paragraph).setLabel(prompt).setCustomId("typed")
TheCodedProf35e73712023-03-10 17:35:35 -0500170 )
171 )
172 .setTitle("Reason")
173 .setCustomId("modal");
174 await buttonInteraction.showModal(modal);
175 let out: ModalSubmitInteraction;
176 try {
177 out = await buttonInteraction.awaitModalSubmit({
178 filter: (i) => i.customId === "modal" && i.user.id === buttonInteraction.user.id,
179 time: 300000
180 });
181 } catch {
182 return null;
183 }
184 await out.deferUpdate();
185 return out.fields.getTextInputValue("typed");
TheCodedProfca29ebb2023-03-10 17:40:09 -0500186};
TheCodedProf35e73712023-03-10 17:35:35 -0500187
188async function modifySuggestion(interaction: ButtonInteraction, accept: boolean) {
189 const message = interaction.message;
PineaFan1dee28f2023-01-16 22:09:07 +0000190 await message.fetch();
191 if (message.embeds.length === 0) return;
TheCodedProf35e73712023-03-10 17:35:35 -0500192 const embed = message.embeds[0]!;
TheCodedProfca29ebb2023-03-10 17:40:09 -0500193 const issueNum = embed.footer!.text;
194 if (!issueNum) return;
TheCodedProf35e73712023-03-10 17:35:35 -0500195 const issue = {
196 owner: "ClicksMinutePer",
197 repo: "Nucleus",
198 issue_number: parseInt(issueNum)
TheCodedProfca29ebb2023-03-10 17:40:09 -0500199 };
TheCodedProf35e73712023-03-10 17:35:35 -0500200 let name = "Unknown";
201 const components: InteractionEditReplyOptions["components"] = [];
TheCodedProfca29ebb2023-03-10 17:40:09 -0500202 switch (interaction.customId) {
TheCodedProf35e73712023-03-10 17:35:35 -0500203 case "accept:Suggestion": {
204 name = "Accepted";
205 await interaction.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -0500206 await client.GitHub.rest.issues.createComment({
207 ...issue,
208 body: "Suggestion accepted by " + interaction.user.tag
209 });
210 components.push(
211 new ActionRowBuilder<ButtonBuilder>().addComponents(
212 new ButtonBuilder()
213 .setCustomId("close:Suggestion")
214 .setLabel("Close")
215 .setStyle(ButtonStyle.Secondary),
216 new ButtonBuilder()
217 .setCustomId("implemented:Suggestion")
218 .setLabel("Implemented")
219 .setStyle(ButtonStyle.Secondary)
220 )
221 );
TheCodedProf35e73712023-03-10 17:35:35 -0500222 break;
223 }
224 case "deny:Suggestion": {
225 name = "Denied";
226 const reason = await getReason(interaction, "Reason for denial");
TheCodedProfca29ebb2023-03-10 17:40:09 -0500227 await client.GitHub.rest.issues.createComment({
228 ...issue,
229 body: "Suggestion denied by " + interaction.user.tag + " for reason:\n>" + reason
230 });
231 await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "not_planned" });
TheCodedProf35e73712023-03-10 17:35:35 -0500232 // await client.GitHub.rest.issues.lock({...issue, lock_reason: "resolved"})
TheCodedProfca29ebb2023-03-10 17:40:09 -0500233 components.push(
234 new ActionRowBuilder<ButtonBuilder>().addComponents(
235 new ButtonBuilder().setCustomId("lock:Suggestion").setLabel("Lock").setStyle(ButtonStyle.Danger)
236 )
237 );
TheCodedProf35e73712023-03-10 17:35:35 -0500238 break;
239 }
240 case "close:Suggestion": {
241 name = "Closed";
242 const reason = await getReason(interaction, "Reason for closing");
TheCodedProfca29ebb2023-03-10 17:40:09 -0500243 await client.GitHub.rest.issues.createComment({
244 ...issue,
245 body: "Suggestion closed by " + interaction.user.tag + " for reason:\n>" + reason
246 });
247 await client.GitHub.rest.issues.update({ ...issue, state: "closed" });
TheCodedProf35e73712023-03-10 17:35:35 -0500248 // await client.GitHub.rest.issues.lock({...issue})
TheCodedProfca29ebb2023-03-10 17:40:09 -0500249 components.push(
250 new ActionRowBuilder<ButtonBuilder>().addComponents(
251 new ButtonBuilder().setCustomId("lock:Suggestion").setLabel("Lock").setStyle(ButtonStyle.Danger)
252 )
253 );
TheCodedProf35e73712023-03-10 17:35:35 -0500254 break;
255 }
256 case "implement:Suggestion": {
257 name = "Implemented";
258 await interaction.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -0500259 await client.GitHub.rest.issues.createComment({ ...issue, body: "Suggestion implemented" });
260 await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "completed" });
261 await client.GitHub.rest.issues.lock({ ...issue, lock_reason: "resolved" });
TheCodedProf35e73712023-03-10 17:35:35 -0500262 break;
263 }
264 case "lock:Suggestion": {
265 name = "Locked";
266 await interaction.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -0500267 await client.GitHub.rest.issues.lock({ ...issue });
TheCodedProf35e73712023-03-10 17:35:35 -0500268 break;
269 }
270 case "spam:Suggestion": {
271 name = "Marked as Spam";
272 await interaction.deferUpdate();
TheCodedProfca29ebb2023-03-10 17:40:09 -0500273 await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "not_planned" });
274 await client.GitHub.rest.issues.lock({ ...issue, lock_reason: "spam" });
TheCodedProf35e73712023-03-10 17:35:35 -0500275 break;
276 }
277 }
278
TheCodedProf46518a42023-02-18 17:08:23 -0500279 const newcolor = accept ? "Success" : "Danger";
TheCodedProf35e73712023-03-10 17:35:35 -0500280 const newEmoji = accept ? "ICONS.ADD" : "ICONS.OPP.ADD";
PineaFan1dee28f2023-01-16 22:09:07 +0000281
282 const newEmbed = new EmojiEmbed()
TheCodedProf35e73712023-03-10 17:35:35 -0500283 .setEmoji(newEmoji)
284 .setTitle(embed!.title!.replace(/.+> /, ""))
PineaFan1dee28f2023-01-16 22:09:07 +0000285 .setDescription(embed!.description!)
TheCodedProf35e73712023-03-10 17:35:35 -0500286 .setFields({
287 name: name + " by",
TheCodedProfca29ebb2023-03-10 17:40:09 -0500288 value: interaction.user.tag
TheCodedProf35e73712023-03-10 17:35:35 -0500289 })
290 .setStatus(newcolor)
291 .setFooter(embed!.footer);
PineaFan1dee28f2023-01-16 22:09:07 +0000292
TheCodedProf35e73712023-03-10 17:35:35 -0500293 await interaction.editReply({
294 embeds: [newEmbed],
295 components: components
296 });
PineaFan1dee28f2023-01-16 22:09:07 +0000297}
298
PineaFan752af462022-12-31 21:59:38 +0000299export async function callback(_client: NucleusClient, interaction: Interaction) {
pineafan63fc5e22022-08-04 22:04:10 +0100300 await interactionCreate(interaction);
Skyler Grey75ea9172022-08-06 10:22:23 +0100301}