From f34158caa6ab1bdb2f58945ddd44b6b8a1a18ec6 Mon Sep 17 00:00:00 2001 From: 1tzEmerald Date: Sat, 9 Nov 2024 02:32:52 +0000 Subject: [PATCH] Update close.js --- Commands/close.js | 215 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 149 insertions(+), 66 deletions(-) diff --git a/Commands/close.js b/Commands/close.js index 7e87d22..e880d9b 100644 --- a/Commands/close.js +++ b/Commands/close.js @@ -17,7 +17,7 @@ module.exports = new Command({ name: "reason", description: "Ticket Close Reason", type: Discord.ApplicationCommandOptionType.String, - }, + } ], permissions: cmdconfig.CloseTicket.Permission, @@ -35,33 +35,33 @@ module.exports = new Command({ const NoPerms = new Discord.EmbedBuilder() .setTitle("Invalid Permissions!") .setDescription(`${msgconfig.Error.IncorrectPerms}\n\nRole Required: \`${supportbot.Roles.StaffMember.Staff}\` or \`${supportbot.Roles.StaffMember.Admin}\``) - .setColor(supportbot.Embed.Colours.Warn); + .setColor(supportbot.Embed.Colours.Warn); if (!interaction.member.roles.cache.has(SupportStaff.id) && !interaction.member.roles.cache.has(Admin.id)) { return interaction.reply({ embeds: [NoPerms] }); } } + const isThread = interaction.channel.type === Discord.ChannelType.PrivateThread; if ( - (supportbot.Ticket.TicketType === "threads" && interaction.channel.type !== Discord.ChannelType.PrivateThread) || + (supportbot.Ticket.TicketType === "threads" && !isThread) || (supportbot.Ticket.TicketType === "channels" && interaction.channel.type !== Discord.ChannelType.GuildText) ) { const NotTicketChannel = new Discord.EmbedBuilder() .setTitle("Invalid Channel!") .setDescription(`This command can only be used in a ${supportbot.Ticket.TicketType === "threads" ? "ticket thread" : "ticket channel"}.`) - .setColor(supportbot.Embed.Colours.Warn); // Ensure valid color + .setColor(supportbot.Embed.Colours.Warn); return interaction.reply({ embeds: [NotTicketChannel], ephemeral: true }); } - await interaction.deferReply(); // Deferring to avoid double replies + await interaction.deferReply(); - // Reading TicketData.json once for efficiency let tickets; try { tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); } catch (err) { - console.error('Error reading ticket data file:', err); + console.error("Error reading ticket data file:", err); return interaction.followUp({ content: "There was an error loading ticket data." }); } @@ -72,15 +72,16 @@ module.exports = new Command({ const Exists = new Discord.EmbedBuilder() .setTitle("No Ticket Found!") .setDescription(msgconfig.Error.NoValidTicket) - .setColor(supportbot.Embed.Colours.Warn); // Ensure valid color + .setColor(supportbot.Embed.Colours.Warn); return interaction.followUp({ embeds: [Exists] }); } let reason = interaction.options?.getString("reason") || "No Reason Provided."; + const ticketUserId = ticket.user; if (supportbot.Ticket.ReviewSystem.Enabled) { - const rating = await collectReviewRating(interaction); - const comment = await collectReviewComment(interaction); + const rating = await collectReviewRating(interaction, ticketUserId); + const comment = await collectReviewComment(interaction, ticketUserId); const reviewChannel = await getChannel(supportbot.Ticket.ReviewSystem.Channel, interaction.guild); const reviewer = supportbot.Ticket.ClaimTickets ? `<@${ticket.claimedBy}>` : null; @@ -103,11 +104,11 @@ module.exports = new Command({ if (supportbot.Ticket.ClaimTickets.Enabled) { reviewEmbed.setDescription( - `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedStaffTitle}** ${reviewer}\n**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${interaction.user.id}>` || `N/A` + `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedStaffTitle}** ${reviewer}\n**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${ticketUserId}>` || `N/A` ); } else { reviewEmbed.setDescription( - `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${interaction.user.id}>` + `**${msgconfig.ReviewSystem.ReviewEmbed.ReviewedByTitle}** <@${ticketUserId}>` ); } @@ -126,11 +127,11 @@ module.exports = new Command({ }, }); -async function collectReviewRating(interaction) { +async function collectReviewRating(interaction, ticketUserId) { const reviewPrompt = new Discord.EmbedBuilder() .setTitle(msgconfig.ReviewSystem.Rate.Title) - .setDescription(msgconfig.ReviewSystem.Rate.Description) - .setColor(supportbot.Embed.Colours.General); // Ensure valid color + .setDescription(`${msgconfig.ReviewSystem.Rate.Description}`) + .setColor(supportbot.Embed.Colours.General); const stars = new Discord.ActionRowBuilder().addComponents( new Discord.StringSelectMenuBuilder() @@ -146,6 +147,7 @@ async function collectReviewRating(interaction) { ); await interaction.followUp({ + content: `<@${ticketUserId}>`, embeds: [reviewPrompt], components: [stars], ephemeral: true, @@ -153,27 +155,27 @@ async function collectReviewRating(interaction) { const starRating = await interaction.channel.awaitMessageComponent({ componentType: Discord.ComponentType.StringSelect, - filter: (i) => i.customId === "starRating" && i.user.id === interaction.user.id, - time: 30000, + filter: (i) => i.customId === "starRating" && i.user.id === ticketUserId, }); - await starRating.deferUpdate(); return starRating.values[0]; } -async function collectReviewComment(interaction) { +async function collectReviewComment(interaction, ticketUserId) { const commentPrompt = new Discord.EmbedBuilder() .setTitle(msgconfig.ReviewSystem.Comment.Title) - .setDescription(msgconfig.ReviewSystem.Comment.Description) - .setColor(supportbot.Embed.Colours.General); // Ensure valid color + .setDescription(`${msgconfig.ReviewSystem.Comment.Description}`) + .setColor(supportbot.Embed.Colours.General); await interaction.followUp({ + content: `<@${ticketUserId}>`, embeds: [commentPrompt], ephemeral: true, }); - const filter = (response) => response.author.id === interaction.user.id; - const commentCollection = await interaction.channel.awaitMessages({ filter, max: 1, time: 30000 }); + const filter = (response) => response.author.id === ticketUserId; + + const commentCollection = await interaction.channel.awaitMessages({ filter, max: 1 }); const comment = commentCollection.first()?.content; return comment && comment.toLowerCase() !== "no" ? comment : "No Comment Provided"; } @@ -181,12 +183,21 @@ async function collectReviewComment(interaction) { async function handleCloseTicket(interaction, reason, ticket, TicketData) { const { getChannel } = interaction.client; - let tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + let tickets; + try { + tickets = JSON.parse(fs.readFileSync("./Data/TicketData.json", "utf8")); + } catch (err) { + console.error("Error reading ticket data:", err); + return interaction.followUp("Failed to load ticket data."); + } + let tUser = interaction.client.users.cache.get(ticket.user); let transcriptChannel = await getChannel(supportbot.Ticket.Log.TicketDataLog, interaction.guild); - if (!transcriptChannel) - return console.log("Ticket Log Missing"); + if (!transcriptChannel) { + console.log("Transcript channel missing or inaccessible"); + return interaction.followUp("Error: Transcript log channel is missing or bot lacks permission."); + } try { tickets.tickets[TicketData].open = false; @@ -194,57 +205,129 @@ async function handleCloseTicket(interaction, reason, ticket, TicketData) { const transcriptEmbed = new Discord.EmbedBuilder() .setTitle(msgconfig.TicketLog.Title) - .setColor(msgconfig.TicketLog.Colour) // Ensure valid color + .setColor(msgconfig.TicketLog.Colour) .setFooter({ text: supportbot.Embed.Footer, iconURL: interaction.user.displayAvatarURL() }) - .setDescription(`> **Ticket:** ${interaction.channel.name} (\`${interaction.channel.id}\`)\n> **User:** ${tUser?.username || "N/A"}#${tUser?.discriminator || "N/A"} (\`${tUser?.id || ticket.user}\`)\n> **Closed by:** <@${interaction.user.id}>`) + .setDescription( + `> **Ticket:** ${interaction.channel.name} (\`${interaction.channel.id}\`)\n` + + `> **User:** ${tUser?.tag || "Unknown User"} (\`${tUser?.id || ticket.user}\`)\n` + + `> **Closed by:** <@${interaction.user.id}>` + ) .addFields({ name: "Reason", value: `\`\`\`${reason}\`\`\``, inline: true }); let msgs = await interaction.channel.messages.fetch({ limit: 100 }); - let html = createTranscriptHTML(interaction, msgs); + let html = createTranscriptHTML(ticket, msgs); - const fileName = `${interaction.channel.name}.html`; - let file = new Discord.AttachmentBuilder(Buffer.from(html), { name: `SPOILER_${fileName}` }); + const fileName = `${interaction.channel.id}-transcript.html`; + fs.writeFileSync(`./Data/Transcripts/${fileName}`, html); - transcriptChannel.send({ + await transcriptChannel.send({ embeds: [transcriptEmbed], - files: [file], + files: [`./Data/Transcripts/${fileName}`], + spoiler: true, }); + + if (interaction.channel.type === Discord.ChannelType.GuildText) { + await interaction.channel.delete(); + } else if (interaction.channel.type === Discord.ChannelType.PrivateThread) { + await interaction.channel.setLocked(true); + await interaction.channel.setArchived(true); + } } catch (err) { - console.log("Error closing ticket:", err); + console.error("Error handling ticket close:", err); + interaction.followUp("An error occurred while closing the ticket."); } - - await interaction.channel.delete(); } -function createTranscriptHTML(interaction, msgs) { - let html = ` - - - - - -

Ticket Transcript

-

Ticket: ${interaction.channel.name}

-

User: ${interaction.user.tag}

-
+function createTranscriptHTML(ticket, reason) { + const messages = ticket.messages || []; + return ` + + + + + + +
+

Ticket Transcript

+

Server Name: Emerald Services

+

Ticket: ${ticket.id}

+

Messages: ${messages.length} Messages

+
+ ${messages.map(msg => ` +
+ User Avatar +
+

${msg.username}

+

${msg.content}

+

${msg.timestamp}

+
+
`).join('')} +
+ Download Transcript +
+ + `; - - msgs.reverse().forEach((msg) => { - html += ` -
- ${msg.author.tag}: ${msg.content} -
- `; - }); - - html += ` -
- - - `; - return html; } + +