From 15318df9e4325c0f89257b44f29f37af499b013a Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 28 Oct 2022 17:32:28 +0100 Subject: [PATCH] feat: `/add` and `/remove` commands --- src/commands/slash/add.js | 110 ++++++++++++++++++++++++++++++++++- src/commands/slash/remove.js | 109 +++++++++++++++++++++++++++++++++- src/i18n/en-GB.yml | 16 +++++ 3 files changed, 233 insertions(+), 2 deletions(-) diff --git a/src/commands/slash/add.js b/src/commands/slash/add.js index 73bd32d..b8a54bf 100644 --- a/src/commands/slash/add.js +++ b/src/commands/slash/add.js @@ -1,5 +1,8 @@ const { SlashCommand } = require('@eartharoid/dbf'); const { ApplicationCommandOptionType } = require('discord.js'); +const ExtendedEmbedBuilder = require('../../lib/embed'); +const { isStaff } = require('../../lib/users'); +const { logTicketEvent } = require('../../lib/logging'); module.exports = class AddSlashCommand extends SlashCommand { constructor(client, options) { @@ -32,5 +35,110 @@ module.exports = class AddSlashCommand 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 }); + + const ticket = await client.prisma.ticket.findUnique({ + include: { guild: true }, + where: { id: interaction.options.getString('ticket', false) || interaction.channel.id }, + }); + + if (!ticket) { + const settings = await client.prisma.guild.findUnique({ where: { id: interaction.guild.id } }); + const getMessage = client.i18n.getLocale(settings.locale); + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: settings.footer, + }) + .setColor(settings.errorColour) + .setTitle(getMessage('misc.invalid_ticket.title')) + .setDescription(getMessage('misc.invalid_ticket.description')), + ], + }); + } + + const getMessage = client.i18n.getLocale(ticket.guild.locale); + + if ( + ticket.id !== interaction.channel.id && + ticket.createdById !== interaction.member.id && + !(await isStaff(interaction.guild, interaction.member.id)) + ) { + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: ticket.guild.footer, + }) + .setColor(ticket.guild.errorColour) + .setTitle(getMessage('commands.slash.add.not_staff.title')) + .setDescription(getMessage('commands.slash.add.not_staff.description')), + ], + }); + } + + /** @type {import("discord.js").TextChannel} */ + const ticketChannel = await interaction.guild.channels.fetch(ticket.id); + const member = interaction.options.getMember('member', true); + + await ticketChannel.permissionOverwrites.edit( + member, + { + AttachFiles: true, + EmbedLinks: true, + ReadMessageHistory: true, + SendMessages: true, + ViewChannel: true, + }, + `${interaction.user.tag} added ${member.user.tag} to the ticket`, + ); + + await ticketChannel.send({ + embeds: [ + new ExtendedEmbedBuilder() + .setColor(ticket.guild.primaryColour) + .setDescription(getMessage('commands.slash.add.added', { + added: member.toString(), + by: interaction.member.toString(), + })), + ], + }); + + await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: ticket.guild.footer, + }) + .setColor(ticket.guild.successColour) + .setTitle(getMessage('commands.slash.add.success.title')) + .setDescription(getMessage('commands.slash.add.success.description', { + member: member.toString(), + ticket: ticketChannel.toString(), + })), + ], + }); + + logTicketEvent(this.client, { + action: 'update', + diff: { + original: {}, + updated: { [getMessage('log.ticket.added')]: member.user.tag }, + }, + target: { + id: ticket.id, + name: `<#${ticket.id}>`, + }, + userId: interaction.user.id, + }); + + } }; \ No newline at end of file diff --git a/src/commands/slash/remove.js b/src/commands/slash/remove.js index 0123fa0..51ca9bf 100644 --- a/src/commands/slash/remove.js +++ b/src/commands/slash/remove.js @@ -1,5 +1,8 @@ const { SlashCommand } = require('@eartharoid/dbf'); const { ApplicationCommandOptionType } = require('discord.js'); +const ExtendedEmbedBuilder = require('../../lib/embed'); +const { isStaff } = require('../../lib/users'); +const { logTicketEvent } = require('../../lib/logging'); module.exports = class RemoveSlashCommand extends SlashCommand { constructor(client, options) { @@ -32,5 +35,109 @@ module.exports = class RemoveSlashCommand 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 }); + + const ticket = await client.prisma.ticket.findUnique({ + include: { guild: true }, + where: { id: interaction.options.getString('ticket', false) || interaction.channel.id }, + }); + + if (!ticket) { + const settings = await client.prisma.guild.findUnique({ where: { id: interaction.guild.id } }); + const getMessage = client.i18n.getLocale(settings.locale); + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: settings.footer, + }) + .setColor(settings.errorColour) + .setTitle(getMessage('misc.invalid_ticket.title')) + .setDescription(getMessage('misc.invalid_ticket.description')), + ], + }); + } + + const getMessage = client.i18n.getLocale(ticket.guild.locale); + + if ( + ticket.id !== interaction.channel.id && + ticket.createdById !== interaction.member.id && + !(await isStaff(interaction.guild, interaction.member.id)) + ) { + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: ticket.guild.footer, + }) + .setColor(ticket.guild.errorColour) + .setTitle(getMessage('commands.slash.remove.not_staff.title')) + .setDescription(getMessage('commands.slash.remove.not_staff.description')), + ], + }); + } + + /** @type {import("discord.js").TextChannel} */ + const ticketChannel = await interaction.guild.channels.fetch(ticket.id); + const member = interaction.options.getMember('member', true); + + if (member.id === client.user.id) { + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder() + .setColor(ticket.guild.errorColour) + .setTitle('❌'), + ], + }); + } + + await ticketChannel.permissionOverwrites.delete(member, `${interaction.user.tag} removed ${member.user.tag} from the ticket`); + + await ticketChannel.send({ + embeds: [ + new ExtendedEmbedBuilder() + .setColor(ticket.guild.primaryColour) + .setDescription(getMessage('commands.slash.remove.removed', { + by: interaction.member.toString(), + removed: member.toString(), + })), + ], + }); + + await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: ticket.guild.footer, + }) + .setColor(ticket.guild.successColour) + .setTitle(getMessage('commands.slash.remove.success.title')) + .setDescription(getMessage('commands.slash.remove.success.description', { + member: member.toString(), + ticket: ticketChannel.toString(), + })), + ], + }); + + logTicketEvent(this.client, { + action: 'update', + diff: { + original: { [getMessage('log.ticket.removed')]: member.user.tag }, + updated: {}, + }, + target: { + id: ticket.id, + name: `<#${ticket.id}>`, + }, + userId: interaction.user.id, + }); + } }; \ No newline at end of file diff --git a/src/i18n/en-GB.yml b/src/i18n/en-GB.yml index 52a0328..a915d69 100644 --- a/src/i18n/en-GB.yml +++ b/src/i18n/en-GB.yml @@ -39,8 +39,12 @@ commands: title: ✅ Pinned message slash: add: + added: ➡️ {added} has been added by {by}. description: Add a member to a ticket name: add + not_staff: + description: Only staff members can add members to others' tickets. + title: ❌ Error options: member: description: The member to add to the ticket @@ -48,6 +52,9 @@ commands: ticket: description: The ticket to add the member to name: ticket + success: + description: "{member} has been added to {ticket}." + title: ✅ Added claim: description: Claim a ticket name: claim @@ -144,8 +151,12 @@ commands: description: Release (unclaim) a ticket name: release remove: + removed: ⬅️ {removed} has been removed by {by}. description: Remove a member from a ticket name: remove + not_staff: + description: Only staff members can removed members from others' tickets. + title: ❌ Error options: member: description: The member to remove from the ticket @@ -153,6 +164,9 @@ commands: ticket: description: The ticket to remove the member from name: ticket + success: + description: "{member} has been removed from {ticket}." + title: ✅ Added tag: description: Use a tag name: tag @@ -243,7 +257,9 @@ log: delete: deleted update: updated ticket: + added: Added members description: "{user} {verb} a ticket" + removed: Removed members ticket: Ticket title: Ticket {verb} verb: