huge changes
This commit is contained in:
@@ -19,10 +19,13 @@ const { CONFIG } = require('../config');
|
||||
const { canRename, makeTicketName, resolveCreatorNickname, minutesFromMs, getOrCreateTicketCategory, cleanupEmptyOverflowCategory, createDiscordTicketAsThread, checkTicketCreationRateLimit, getSenderLocal, toDiscordSafeName } = require('../services/tickets');
|
||||
const { sendTicketClosedEmail } = require('../services/gmail');
|
||||
const { getTicketActionRow } = require('../utils/ticketComponents');
|
||||
const { sanitizeEmbedText, truncateEmbedDescription, truncateEmbedField, enforceEmbedLimit } = require('../utils');
|
||||
const { setEmailRouting } = require('../services/guildSettings');
|
||||
const { enqueueRename } = require('../services/channelQueue');
|
||||
const { runEscalation, runDeescalation } = require('./commands');
|
||||
const { trackInteraction, trackError } = require('./analytics');
|
||||
const { pendingCloses } = require('./pendingCloses');
|
||||
const { increment } = require('../services/patternStore');
|
||||
|
||||
const Ticket = mongoose.model('Ticket');
|
||||
const Transcript = mongoose.model('Transcript');
|
||||
@@ -131,7 +134,25 @@ async function handleButton(interaction) {
|
||||
}
|
||||
|
||||
if (interaction.customId === 'confirm_close') {
|
||||
return handleConfirmClose(interaction, ticket);
|
||||
const timerSeconds = CONFIG.FORCE_CLOSE_TIMER;
|
||||
if (pendingCloses.has(interaction.channel.id)) {
|
||||
return interaction.reply({ content: 'A close is already pending for this ticket.', ephemeral: true });
|
||||
}
|
||||
await interaction.update({ content: `Closing ticket in ${timerSeconds} seconds. Use \`/cancel-close\` to abort.`, components: [] });
|
||||
const timerId = setTimeout(async () => {
|
||||
pendingCloses.delete(interaction.channel.id);
|
||||
const freshTicket = await Ticket.findOne({ discordThreadId: interaction.channel.id }).lean();
|
||||
if (!freshTicket || freshTicket.status === 'closed') return;
|
||||
const { logTicketEvent } = require('../services/debugLog');
|
||||
logTicketEvent('Force-close timer fired', [
|
||||
{ name: 'Ticket', value: interaction.channel.name || interaction.channel.id },
|
||||
{ name: 'Set by', value: interaction.user.tag },
|
||||
{ name: 'Duration', value: `${timerSeconds}s` }
|
||||
]).catch(() => {});
|
||||
await handleConfirmClose(interaction, freshTicket);
|
||||
}, timerSeconds * 1000);
|
||||
pendingCloses.set(interaction.channel.id, { timeout: timerId, userId: interaction.user.id, username: interaction.user.tag });
|
||||
return;
|
||||
}
|
||||
|
||||
if (interaction.customId === 'cancel_close') {
|
||||
@@ -294,6 +315,8 @@ async function handleClaim(interaction, ticket) {
|
||||
}
|
||||
|
||||
if (isClaimed && !isClaimedByMe && !CONFIG.ALLOW_CLAIM_OVERWRITE) {
|
||||
const { logSecurity } = require('../services/debugLog');
|
||||
logSecurity('Unauthorized button attempt', interaction.user, interaction.customId).catch(() => {});
|
||||
return interaction.reply({
|
||||
content: `This ticket is already claimed by **${freshTicket.claimedBy}**.`,
|
||||
ephemeral: true
|
||||
@@ -307,6 +330,8 @@ async function handleClaim(interaction, ticket) {
|
||||
);
|
||||
freshTicket.claimedBy = claimerLabel;
|
||||
freshTicket.claimerId = interaction.user.id;
|
||||
increment('staff_claims', interaction.user.id, 'today');
|
||||
increment('staff_claims', interaction.user.id, 'week');
|
||||
|
||||
// Resolve claimerEmoji from STAFF_EMOJIS map (fallback to CLAIMER_EMOJI_FALLBACK)
|
||||
const claimerEmoji = CONFIG.STAFF_EMOJIS.get(interaction.user.id) || CONFIG.CLAIMER_EMOJI_FALLBACK;
|
||||
@@ -358,6 +383,8 @@ async function handleClaim(interaction, ticket) {
|
||||
.setColor(CONFIG.EMBED_COLOR_CLAIMED)
|
||||
.setFooter({ text: `Claimed by ${claimerLabel}` });
|
||||
await interaction.followUp({ embeds: [claimEmbed] });
|
||||
const { addMemberToStaffThread } = require('../services/staffThread');
|
||||
await addMemberToStaffThread(interaction.channel, interaction.user.id).catch(() => {});
|
||||
} else {
|
||||
// Unclaim
|
||||
await Ticket.updateOne(
|
||||
@@ -415,6 +442,10 @@ async function handleClaim(interaction, ticket) {
|
||||
// --- CONFIRM CLOSE ---
|
||||
async function handleConfirmClose(interaction, ticket) {
|
||||
const closedAt = new Date();
|
||||
increment('staff_closes', interaction.user.id, 'today');
|
||||
if (!ticket.ticketTag) {
|
||||
increment('untagged_closes', 'total', 'today');
|
||||
}
|
||||
try {
|
||||
await interaction.update({ content: 'Archiving and closing...', components: [] });
|
||||
} catch {
|
||||
@@ -669,35 +700,64 @@ async function handleTicketModal(interaction) {
|
||||
|
||||
const displayName = interaction.member?.displayName || interaction.user.username;
|
||||
|
||||
// Welcome embed (dark grey #1e2124)
|
||||
const welcomeEmbed = new EmbedBuilder()
|
||||
.setDescription(CONFIG.TICKET_WELCOME_MESSAGE)
|
||||
.setColor(CONFIG.EMBED_COLOR_INFO)
|
||||
.setFooter({ text: 'Indifferent Broccoli Tickets' });
|
||||
|
||||
// Ticket details embed (dark) – short labels, trimmed description
|
||||
const descTrimmed = description.length > 500 ? description.slice(0, 497) + '…' : description;
|
||||
|
||||
const welcomeEmbed = new EmbedBuilder()
|
||||
.setTitle("We got your ticket.")
|
||||
.setDescription("We'll be with you as soon as possible.")
|
||||
.setColor(5763719)
|
||||
.setThumbnail("https://indifferentbroccoli.com/img/broccoli_shadow_square.png")
|
||||
.setFooter({ text: "indifferent broccoli tickets (:|)", iconURL: "https://i.ibb.co/sJdytfFM/Untitled-design-6.png" });
|
||||
|
||||
const infoEmbed = new EmbedBuilder()
|
||||
.setColor(CONFIG.EMBED_COLOR_INFO)
|
||||
.setColor(5763719)
|
||||
.setDescription(truncateEmbedDescription(
|
||||
`**Account Email:**\n\`\`\`\n${sanitizeEmbedText(email)}\n\`\`\`\n` +
|
||||
`**Game:**\n\`\`\`\n${sanitizeEmbedText(game) || "Not specified"}\n\`\`\`\n` +
|
||||
`**What do you need help with?**\n\`\`\`\n${sanitizeEmbedText(descTrimmed)}\n\`\`\``
|
||||
));
|
||||
|
||||
const resourcesEmbed = new EmbedBuilder()
|
||||
.setTitle("We're ~~happy~~ indifferent to help. :indifferentbroccoli:")
|
||||
.setDescription("Please feel free to add any additional information to the ticket, including recent changes to the server, if any.")
|
||||
.setColor(5763719)
|
||||
.addFields(
|
||||
{ name: 'Email', value: email, inline: true },
|
||||
{ name: 'Game', value: game || 'Not specified', inline: true },
|
||||
{ name: 'Description', value: descTrimmed, inline: false }
|
||||
{ name: "Check out our wiki for guides:", value: "[Indifferent Broccolipedia](https://wiki.indifferentbroccoli.com)", inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
.setFooter({ text: "indifferent broccoli tickets (:|)", iconURL: "https://i.ibb.co/sJdytfFM/Untitled-design-6.png" });
|
||||
|
||||
const actionRow = getTicketActionRow({ escalationTier: 0 });
|
||||
|
||||
const welcomeMsg = await channel.send({
|
||||
content: `Hey There ${interaction.user} 🥦`,
|
||||
embeds: [welcomeEmbed, infoEmbed],
|
||||
components: [actionRow]
|
||||
});
|
||||
enforceEmbedLimit([welcomeEmbed, infoEmbed, resourcesEmbed]);
|
||||
try {
|
||||
const welcomeMsg = await channel.send({
|
||||
content: `Hey There ${interaction.user} 🥦`,
|
||||
embeds: [welcomeEmbed, infoEmbed, resourcesEmbed],
|
||||
components: [actionRow]
|
||||
});
|
||||
|
||||
await Ticket.updateOne(
|
||||
{ discordThreadId: channel.id },
|
||||
{ $set: { welcomeMessageId: welcomeMsg.id } }
|
||||
);
|
||||
await Ticket.updateOne(
|
||||
{ discordThreadId: channel.id },
|
||||
{ $set: { welcomeMessageId: welcomeMsg.id } }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('welcomeMessageId-save', err);
|
||||
}
|
||||
|
||||
const { createStaffThread } = require('../services/staffThread');
|
||||
await createStaffThread(channel, interaction.client).catch(() => {});
|
||||
|
||||
if (CONFIG.PIN_INITIAL_MESSAGE_ENABLED && welcomeMsg) {
|
||||
const { pinMessage } = require('../services/pinMessage');
|
||||
await pinMessage(welcomeMsg, interaction.client).catch(() => {});
|
||||
}
|
||||
|
||||
increment('user_tickets', interaction.user.id, 'today');
|
||||
increment('user_tickets', interaction.user.id, 'week');
|
||||
if (game) {
|
||||
increment('game_tickets', game, 'today');
|
||||
increment('game_tickets', game, 'week');
|
||||
}
|
||||
|
||||
await interaction.deleteReply().catch(() => {});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user