From c6f1261478fc29f261fdd0d32a7fb84feea66b76 Mon Sep 17 00:00:00 2001 From: Isaac Date: Wed, 26 Oct 2022 14:13:45 +0100 Subject: [PATCH] feat: add `/tickets` command --- src/commands/slash/force-close.js | 2 +- src/commands/slash/help.js | 4 +- src/commands/slash/tickets.js | 103 +++++++++++++++++++++++++++++- src/i18n/en-GB.yml | 30 +++++++-- 4 files changed, 129 insertions(+), 10 deletions(-) diff --git a/src/commands/slash/force-close.js b/src/commands/slash/force-close.js index ffdf9b9..af13a34 100644 --- a/src/commands/slash/force-close.js +++ b/src/commands/slash/force-close.js @@ -81,7 +81,7 @@ module.exports = class ForceCloseSlashCommand extends SlashCommand { const getMessage = this.client.i18n.getLocale(settings.locale); let ticket; - if (!isStaff(interaction.guild, interaction.user.id)) { // if user is not staff + if (!(await isStaff(interaction.guild, interaction.user.id))) { // if user is not staff return await interaction.editReply({ embeds: [ new ExtendedEmbedBuilder({ diff --git a/src/commands/slash/help.js b/src/commands/slash/help.js index f5e5c0b..aaa8192 100644 --- a/src/commands/slash/help.js +++ b/src/commands/slash/help.js @@ -36,7 +36,7 @@ module.exports = class ClaimSlashCommand extends SlashCommand { .filter(c => c.type === 1) .map(c => `> : ${c.description}`) .join('\n'); - const ticket = client.application.commands.cache.find(c => c.name === 'new'); + const newCommand = client.application.commands.cache.find(c => c.name === 'new'); const fields = [ { name: getMessage('commands.slash.help.response.commands'), @@ -76,7 +76,7 @@ module.exports = class ClaimSlashCommand extends SlashCommand { .setTitle(getMessage('commands.slash.help.title')) .setDescription(staff ? `**Discord Tickets v${version} by eartharoid.**` - : getMessage('commands.slash.help.response.description', { command: `` })) + : getMessage('commands.slash.help.response.description', { command: `` })) .setFields(fields), ], }); diff --git a/src/commands/slash/tickets.js b/src/commands/slash/tickets.js index 94a7cce..0f71997 100644 --- a/src/commands/slash/tickets.js +++ b/src/commands/slash/tickets.js @@ -1,5 +1,9 @@ const { SlashCommand } = require('@eartharoid/dbf'); const { ApplicationCommandOptionType } = require('discord.js'); +const { isStaff } = require('../../lib/users'); +const ExtendedEmbedBuilder = require('../../lib/embed'); +const Cryptr = require('cryptr'); +const { decrypt } = new Cryptr(process.env.ENCRYPTION_KEY); module.exports = class TicketsSlashCommand extends SlashCommand { constructor(client, options) { @@ -42,5 +46,102 @@ module.exports = class TicketsSlashCommand extends SlashCommand { }); } - async run(interaction) { } + /** + * @param {import("discord.js").ChatInputCommandInteraction} interaction + */ + async run(interaction) { + /** @type {import("client")} */ + const client = this.client; + + await interaction.deferReply({ ephemeral: true }); + await client.application.commands.fetch(); + + const member = interaction.options.getMember('member', false) ?? interaction.member; + const ownOrOther = member.id === interaction.member.id ? 'own' : 'other'; + const settings = await client.prisma.guild.findUnique({ where: { id: interaction.guild.id } }); + const getMessage = client.i18n.getLocale(settings.locale); + + if (member.id !== interaction.member.id && !(await isStaff(interaction.guild, interaction.member.id))) { + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: settings.footer, + }) + .setColor(settings.errorColour) + .setTitle(getMessage('commands.slash.tickets.not_staff.title')) + .setDescription(getMessage('commands.slash.tickets.not_staff.description')), + ], + }); + } + + const fields = []; + + const open = await client.prisma.ticket.findMany({ + include: { category: true }, + where: { + createdById: member.id, + guildId: interaction.guild.id, + open: true, + }, + }); + + const closed = await client.prisma.ticket.findMany({ + include: { category: true }, + orderBy: { createdAt: 'desc' }, + where: { + createdById: member.id, + guildId: interaction.guild.id, + open: false, + }, + }); + + if (open.length >= 1) { + fields.push({ + name: getMessage('commands.slash.tickets.response.fields.open.name'), + value: open.map(ticket =>{ + const topic = ticket.topic ? `- \`${decrypt(ticket.topic).replace(/\n/g, ' ').slice(0, 30) }\`` : ''; + return `> <#${ticket.id}> ${topic}`; + }).join('\n'), + }); + } + + if (closed.length === 0) { + const newCommand = client.application.commands.cache.find(c => c.name === 'new'); + fields.push({ + name: getMessage('commands.slash.tickets.response.fields.closed.name'), + value: getMessage(`commands.slash.tickets.response.fields.closed.none.${ownOrOther}`, { + new: ``, + user: member.user.toString(), + }), + }); + } else { + fields.push({ + name: getMessage('commands.slash.tickets.response.fields.closed.name'), + value: closed.slice(0, 10).map(ticket => { // max 10 rows + const topic = ticket.topic ? `- \`${decrypt(ticket.topic).replace(/\n/g, ' ').slice(0, 30)}\`` : ''; + return `> ${ticket.category.name} #${ticket.number} ${topic}`; + }).join('\n'), + }); + } + + const embed = new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: settings.footer, + }) + .setColor(settings.primaryColour) + .setAuthor({ + iconURL: member.displayAvatarURL(), + name: member.displayName, + }) + .setTitle(getMessage(`commands.slash.tickets.response.title.${ownOrOther}`, { displayName: member.displayName })) + .setFields(fields); + + if (settings.archive && !client.config.overrides.disableArchives) { + const transcriptCommand = client.application.commands.cache.find(c => c.name === 'transcript'); + embed.setDescription(getMessage('commands.slash.tickets.response.description', { transcript: `` })); + } + + return await interaction.editReply({ embeds: [embed] }); + } }; \ No newline at end of file diff --git a/src/i18n/en-GB.yml b/src/i18n/en-GB.yml index f2eb93f..52a0328 100644 --- a/src/i18n/en-GB.yml +++ b/src/i18n/en-GB.yml @@ -67,8 +67,8 @@ commands: force-close: confirm_multiple: description: > - You are about to close **{count}** tickets that have been inactive for - more than `{time}`: + You are about to close **{count}** tickets that have been inactive + for more than `{time}`: {tickets} title: ❓ Are you sure? @@ -85,8 +85,7 @@ commands: options: category: description: >- - Close all tickets in the specified category (can be used with - `time`) + Close all tickets in the specified category (can be used with `time`) name: category reason: description: The reason for closing the ticket(s) @@ -166,11 +165,30 @@ commands: name: tag tickets: description: List your own or someone else's tickets + fields: name: tickets + not_staff: + description: Only staff members can view others' tickets. + title: ❌ Error options: member: description: The member to list the tickets of name: member + response: + description: Use {transcript} to download the transcript of a ticket. + fields: + closed: + name: Closed tickets + none: + other: "{user} hasn't made any tickets." + own: | + You haven't made any tickets. + Use {new} to open a ticket. + open: + name: Open tickets + title: + other: "{displayName}'s tickets" + own: Your tickets topic: description: Change the topic of a ticket name: topic @@ -274,8 +292,8 @@ misc: - ❌ You already have %d open tickets missing_roles: description: >- - You do not have the roles required to be able to create a ticket in this - category. + You do not have the roles required to be able to create a ticket in + this category. title: ❌ Insufficient roles no_categories: description: No ticket categories have been configured.