From 4092b86a1e9fe02d9eba86b5c8104f757edafaeb Mon Sep 17 00:00:00 2001 From: pineafan Date: Fri, 20 May 2022 19:27:23 +0100 Subject: [PATCH 1/2] changes to how deleting tickets works, and UI when creating mod tickets --- src/automations/createModActionTicket.ts | 3 +- src/automations/tickets/delete.ts | 154 +++++++++++------------ src/commands/mod/mute.ts | 1 - src/commands/mod/nick.ts | 8 +- src/commands/mod/purge.ts | 1 - src/commands/mod/unnamed.ts | 6 +- src/commands/mod/warn.ts | 10 +- src/utils/confirmationMessage.ts | 54 ++++++-- 8 files changed, 133 insertions(+), 104 deletions(-) diff --git a/src/automations/createModActionTicket.ts b/src/automations/createModActionTicket.ts index 4de2924..ef317b7 100644 --- a/src/automations/createModActionTicket.ts +++ b/src/automations/createModActionTicket.ts @@ -3,7 +3,7 @@ import readConfig from '../utils/readConfig.js' import generateEmojiEmbed from '../utils/generateEmojiEmbed.js'; import getEmojiByName from "../utils/getEmojiByName.js"; -export async function create(guild: Discord.Guild, member: Discord.User, client) { +export async function create(guild: Discord.Guild, member: Discord.User, createdBy: Discord.User, client) { let config = await readConfig(guild.id); // @ts-ignore const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger @@ -70,6 +70,7 @@ export async function create(guild: Discord.Guild, member: Discord.User, client) }, list: { ticketFor: entry(member.id, renderUser(member)), + createdBy: entry(createdBy.id, renderUser(createdBy)), created: entry(new Date().getTime(), renderDelta(new Date().getTime())), ticketChannel: entry(c.id, renderChannel(c)), }, diff --git a/src/automations/tickets/delete.ts b/src/automations/tickets/delete.ts index 32315bc..17d889a 100644 --- a/src/automations/tickets/delete.ts +++ b/src/automations/tickets/delete.ts @@ -11,7 +11,7 @@ export default async function (interaction) { let channel = (interaction.channel as Discord.TextChannel) if (!channel.parent || config.tickets.category != channel.parent.id) { return interaction.reply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") + .setTitle("Deleting Ticket...") .setDescription("This ticket is not in your tickets category, so cannot be deleted. You cannot run close in a thread.") // TODO bridge to cross later! .setStatus("Danger") .setEmoji("CONTROL.BLOCKCROSS") @@ -19,96 +19,92 @@ export default async function (interaction) { } let status = channel.topic.split(" ")[1]; if (status == "Archived") { - interaction.reply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") - .setDescription("This ticket will be deleted in 3 seconds.") + await interaction.reply({embeds: [new generateEmojiEmbed() + .setTitle("Delete Ticket") + .setDescription("Your ticket is being deleted...") .setStatus("Danger") .setEmoji("GUILD.TICKET.CLOSE") ]}); - setTimeout(async () => { - let data = { - meta:{ - type: 'ticketClosed', - displayName: 'Ticket Closed', - calculateType: true, - color: NucleusColors.red, - emoji: 'GUILD.TICKET.CLOSE', - timestamp: new Date().getTime() - }, - list: { - ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), - closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), - closed: entry(new Date().getTime(), renderDelta(new Date().getTime())) - }, - hidden: { - guild: interaction.guild.id - } + let data = { + meta:{ + type: 'ticketDeleted', + displayName: 'Ticket Deleted', + calculateType: true, + color: NucleusColors.red, + emoji: 'GUILD.TICKET.CLOSE', + timestamp: new Date().getTime() + }, + list: { + ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), + deletedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), + closed: entry(new Date().getTime(), renderDelta(new Date().getTime())) + }, + hidden: { + guild: interaction.guild.id } - log(data, interaction.client); - interaction.channel.delete(); - }, 3000); + } + log(data, interaction.client); + interaction.channel.delete(); return; } else if (status == "Active") { - interaction.reply({embeds: [new generateEmojiEmbed() + await interaction.reply({embeds: [new generateEmojiEmbed() .setTitle("Close Ticket") - .setDescription("This ticket will be archived in 3 seconds.") + .setDescription("Your ticket is being closed...") .setStatus("Warning") .setEmoji("GUILD.TICKET.ARCHIVED") ]}); - setTimeout(async () =>{ - let overwrites = [ - { - id: channel.topic.split(" ")[0], - deny: ["VIEW_CHANNEL"], - type: "member" - }, - { - id: interaction.guild.id, - deny: ["VIEW_CHANNEL"], - type: "role" - } - ] as Discord.OverwriteResolvable[]; - if (config.tickets.supportRole != null) { - overwrites.push({ - id: interaction.guild.roles.cache.get(config.tickets.supportRole), - allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"], - type: "role" - }) + let overwrites = [ + { + id: channel.topic.split(" ")[0], + deny: ["VIEW_CHANNEL"], + type: "member" + }, + { + id: interaction.guild.id, + deny: ["VIEW_CHANNEL"], + type: "role" } - channel.edit({permissionOverwrites: overwrites}) - channel.setTopic(`${channel.topic.split(" ")[0]} Archived`); - let data = { - meta:{ - type: 'ticketArchive', - displayName: 'Ticket Archived', - calculateType: true, - color: NucleusColors.yellow, - emoji: 'GUILD.TICKET.ARCHIVED', - timestamp: new Date().getTime() - }, - list: { - ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), - archivedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), - archived: entry(new Date().getTime(), renderDelta(new Date().getTime())), - ticketChannel: entry(channel.id, renderChannel(channel)), - }, - hidden: { - guild: interaction.guild.id - } + ] as Discord.OverwriteResolvable[]; + if (config.tickets.supportRole != null) { + overwrites.push({ + id: interaction.guild.roles.cache.get(config.tickets.supportRole), + allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"], + type: "role" + }) + } + channel.edit({permissionOverwrites: overwrites}) + channel.setTopic(`${channel.topic.split(" ")[0]} Archived`); + let data = { + meta:{ + type: 'ticketClosed', + displayName: 'Ticket Closed', + calculateType: true, + color: NucleusColors.yellow, + emoji: 'GUILD.TICKET.ARCHIVED', + timestamp: new Date().getTime() + }, + list: { + ticketFor: entry(channel.topic.split(" ")[0], renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)), + closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), + closed: entry(new Date().getTime(), renderDelta(new Date().getTime())), + ticketChannel: entry(channel.id, renderChannel(channel)), + }, + hidden: { + guild: interaction.guild.id } - log(data, interaction.client); - await interaction.editReply({embeds: [new generateEmojiEmbed() - .setTitle("Close Ticket") - .setDescription("This ticket has been archived.\nType `/ticket close` to delete it.") - .setStatus("Warning") - .setEmoji("GUILD.TICKET.ARCHIVED") // TODO:[Premium] Add a transcript option ||\----/|| <- the bridge we will cross when we come to it - ], components: [new MessageActionRow().addComponents([new MessageButton() - .setLabel("Close") - .setStyle("DANGER") - .setCustomId("closeticket") - .setEmoji(getEmojiByName("CONTROL.CROSS", "id")) - ])]}); - }, 3000); + } + log(data, interaction.client); + await interaction.editReply({embeds: [new generateEmojiEmbed() + .setTitle("Close Ticket") + .setDescription("This ticket has been closed.\nType `/ticket close` again to delete it.") + .setStatus("Warning") + .setEmoji("GUILD.TICKET.ARCHIVED") // TODO:[Premium] Add a transcript option ||\----/|| <- the bridge we will cross when we come to it + ], components: [new MessageActionRow().addComponents([new MessageButton() + .setLabel("Delete") + .setStyle("DANGER") + .setCustomId("closeticket") + .setEmoji(getEmojiByName("CONTROL.CROSS", "id")) + ])]}); return; } } diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts index d81a5cc..b2cc94e 100644 --- a/src/commands/mod/mute.ts +++ b/src/commands/mod/mute.ts @@ -6,7 +6,6 @@ import getEmojiByName from "../../utils/getEmojiByName.js"; import confirmationMessage from "../../utils/confirmationMessage.js"; import keyValueList from "../../utils/generateKeyValueList.js"; import humanizeDuration from "humanize-duration"; -import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js"; import readConfig from "../../utils/readConfig.js"; const command = (builder: SlashCommandSubcommandBuilder) => diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts index cd3a7af..e8463f4 100644 --- a/src/commands/mod/nick.ts +++ b/src/commands/mod/nick.ts @@ -29,10 +29,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") == "yes" ? '' : ' not'}** be notified\n\n` + `Are you sure you want to ${interaction.options.getString("name") ? "change" : "clear"} <@!${(interaction.options.getMember("user") as GuildMember).id}>'s nickname?`) .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() @@ -96,7 +96,7 @@ const callback = async (interaction: CommandInteraction) => { await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.NICKNAME.${failed ? "YELLOW" : "GREEN"}`) .setTitle(`Nickname`) - .setDescription("The members nickname was changed" + (failed ? ", but was not notified" : "")) + .setDescription("The members nickname was changed" + (failed ? ", but was not notified" : "") + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus(failed ? "Warning" : "Success") ], components: []}) } else { diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts index e388ea0..924e507 100644 --- a/src/commands/mod/purge.ts +++ b/src/commands/mod/purge.ts @@ -5,7 +5,6 @@ import confirmationMessage from "../../utils/confirmationMessage.js"; import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js"; import keyValueList from "../../utils/generateKeyValueList.js"; import getEmojiByName from "../../utils/getEmojiByName.js"; -import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js"; const command = (builder: SlashCommandSubcommandBuilder) => builder diff --git a/src/commands/mod/unnamed.ts b/src/commands/mod/unnamed.ts index 20ebc30..ca0bcef 100644 --- a/src/commands/mod/unnamed.ts +++ b/src/commands/mod/unnamed.ts @@ -129,10 +129,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n` + `Are you sure you want to mute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`) // TODO .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts index 3f63cce..ce54cfb 100644 --- a/src/commands/mod/warn.ts +++ b/src/commands/mod/warn.ts @@ -30,10 +30,10 @@ const callback = async (interaction: CommandInteraction) => { + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n` + `Are you sure you want to warn <@!${(interaction.options.getMember("user") as GuildMember).id}>?`) .setColor("Danger") - .addCustomCallback( + .addCustomBoolean( "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)), - () => { create(interaction.guild, interaction.options.getUser("user"), interaction.client)}, - "An appeal ticket was created") + async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client), + "An appeal ticket will be created when Confirm is clicked") // pluralize("day", interaction.options.getInteger("delete")) // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" } .send() @@ -85,7 +85,7 @@ const callback = async (interaction: CommandInteraction) => { await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.WARN.GREEN`) .setTitle(`Warn`) - .setDescription("The user was warned") + .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus("Success") ], components: []}) } else { @@ -135,7 +135,7 @@ const callback = async (interaction: CommandInteraction) => { return await interaction.editReply({embeds: [new generateEmojiEmbed() .setEmoji(`PUNISH.WARN.GREEN`) .setTitle(`Warn`) - .setDescription("The user was warned") + .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``)) .setStatus("Success") ], components: []}) } else { diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts index dd97603..7a06d83 100644 --- a/src/utils/confirmationMessage.ts +++ b/src/utils/confirmationMessage.ts @@ -14,6 +14,8 @@ class confirmationMessage { customCallbackString: string = ""; customCallbackClicked: boolean = false; customCallbackResponse: any = null; + customBoolean: () => any; + customBooleanClicked: boolean = null; inverted: boolean; constructor(interaction: CommandInteraction) { @@ -23,8 +25,9 @@ class confirmationMessage { this.emoji = ""; this.description = ""; this.color = ""; - this.inverted = false - this.customCallback = () => {} + this.inverted = false; + this.customCallback = () => {}; + this.customBoolean = () => {}; } setTitle(title: string) { this.title = title; return this } @@ -33,12 +36,23 @@ class confirmationMessage { setColor(color: string) { this.color = color; return this } setInverted(inverted: boolean) { this.inverted = inverted; return this } addCustomCallback(title: string, disabled: boolean, callback: () => any, callbackClicked: string) { + if (this.customButtonTitle) return this this.customButtonTitle = title; this.customButtonDisabled = disabled; this.customCallback = callback; this.customCallbackString = callbackClicked; return this; } + addCustomBoolean(title: string, disabled: boolean, callback: () => any, callbackClicked: string) { + if (this.customButtonTitle) return this + this.customButtonTitle = title; + this.customButtonDisabled = disabled; + this.customBoolean = callback; + this.customCallbackString = callbackClicked; + this.customBooleanClicked = false; + return this; + } + async send(editOnly?: boolean) { while (true) { @@ -49,7 +63,7 @@ class confirmationMessage { .setTitle(this.title) .setDescription(this.description) .setStatus(this.color) - .setFooter({text: this.customCallbackClicked ? this.customCallbackString : ""}) + .setFooter({text: (this.customBooleanClicked ?? this.customCallbackClicked) ? this.customCallbackString : ""}) ], components: [ new MessageActionRow().addComponents([ @@ -66,7 +80,10 @@ class confirmationMessage { ].concat(this.customButtonTitle ? [new Discord.MessageButton() .setCustomId("custom") .setLabel(this.customButtonTitle) - .setStyle("PRIMARY") + .setStyle(this.customBooleanClicked !== null ? + ( this.customBooleanClicked ? "SUCCESS" : "PRIMARY" ) : + "PRIMARY" + ) .setDisabled(this.customButtonDisabled) .setEmoji(getEmojiByName("CONTROL.TICKET", "id")) ] : [])) @@ -84,19 +101,36 @@ class confirmationMessage { try { component = await (m as Message).awaitMessageComponent({filter: (m) => m.user.id === this.interaction.user.id, time: 2.5 * 60 * 1000}); } catch (e) { - return { success: false, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + return { + success: false, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } if (component.customId === "yes") { component.deferUpdate(); - return { success: true, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + if (this.customBooleanClicked === true) this.customCallbackResponse = await this.customBoolean(); + return { + success: true, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } else if (component.customId === "no") { component.deferUpdate(); - return { success: false, buttonClicked: this.customCallbackClicked, response: this.customCallbackResponse }; + return { + success: false, + buttonClicked: this.customBooleanClicked ?? this.customCallbackClicked, + response: this.customCallbackResponse + }; } else if (component.customId === "custom") { component.deferUpdate(); - this.customCallbackResponse = this.customCallback(); - this.customCallbackClicked = true; - this.customButtonDisabled = true; + if (this.customBooleanClicked !== null) { + this.customBooleanClicked = !this.customBooleanClicked; + } else { + this.customCallbackResponse = await this.customCallback(); + this.customCallbackClicked = true; + this.customButtonDisabled = true; + } editOnly = true; } } From 30b5fdaddec33de73efa543d201c8ff9b945dbf0 Mon Sep 17 00:00:00 2001 From: PineappleFan Date: Sun, 22 May 2022 15:41:47 +0100 Subject: [PATCH 2/2] Fixed some bad grammar --- src/commands/mod/nick.ts | 2 +- src/commands/mod/warn.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts index e8463f4..6a0410a 100644 --- a/src/commands/mod/nick.ts +++ b/src/commands/mod/nick.ts @@ -47,7 +47,7 @@ const callback = async (interaction: CommandInteraction) => { .setTitle("Nickname changed") .setDescription(`Your nickname was ${interaction.options.getString("name") ? "changed" : "cleared"} in ${interaction.guild.name}.` + (interaction.options.getString("name") ? ` it is now: ${interaction.options.getString("name")}` : "") + "\n\n" + - (confirmation.buttonClicked ? `You can appeal this in this ticket: <#${confirmation.response}>` : ``)) + (confirmation.buttonClicked ? `You can appeal this here: <#${confirmation.response}>` : ``)) .setStatus("Danger") ] }) diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts index ce54cfb..715777e 100644 --- a/src/commands/mod/warn.ts +++ b/src/commands/mod/warn.ts @@ -47,7 +47,7 @@ const callback = async (interaction: CommandInteraction) => { .setTitle("Warned") .setDescription(`You have been warned in ${interaction.guild.name}` + (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : ".") + "\n\n" + - (confirmation.buttonClicked ? `You can appeal this in this ticket: <#${confirmation.response}>` : ``)) + (confirmation.buttonClicked ? `You can appeal this here ticket: <#${confirmation.response}>` : ``)) .setStatus("Danger") ] })