staff notifications

This commit is contained in:
indifferentketchup
2026-04-06 23:53:32 -05:00
parent 8c95b5eb8d
commit c5d7539677
12 changed files with 379 additions and 108 deletions

View File

@@ -16,7 +16,7 @@ const {
} = require('discord.js');
const { mongoose } = require('../db-connection');
const { CONFIG } = require('../config');
const { canRename, makeTicketName, minutesFromMs, getOrCreateTicketCategory, cleanupEmptyOverflowCategory, createDiscordTicketAsThread, checkTicketCreationRateLimit, getSenderLocal } = require('../services/tickets');
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 { setEmailRouting } = require('../services/guildSettings');
@@ -144,16 +144,24 @@ async function handleButton(interaction) {
if (currentTier >= 2) {
return interaction.reply({ content: 'This ticket is already at tier 3 support.', ephemeral: true });
}
const choiceRow = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId('escalate_to_tier2')
.setLabel('To Tier 2')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('escalate_to_tier3')
.setLabel('To Tier 3')
.setStyle(ButtonStyle.Secondary)
);
const escalateButtons = [];
if (currentTier < 1) {
escalateButtons.push(
new ButtonBuilder()
.setCustomId('escalate_to_tier2')
.setLabel('To Tier 2')
.setStyle(ButtonStyle.Secondary)
);
}
if (currentTier < 2) {
escalateButtons.push(
new ButtonBuilder()
.setCustomId('escalate_to_tier3')
.setLabel('To Tier 3')
.setStyle(ButtonStyle.Secondary)
);
}
const choiceRow = new ActionRowBuilder().addComponents(escalateButtons);
return interaction.reply({
content: 'Escalate to which tier?',
components: [choiceRow],
@@ -302,29 +310,12 @@ async function handleClaim(interaction, ticket) {
// Resolve claimerEmoji from STAFF_EMOJIS map (fallback to CLAIMER_EMOJI_FALLBACK)
const claimerEmoji = CONFIG.STAFF_EMOJIS.get(interaction.user.id) || CONFIG.CLAIMER_EMOJI_FALLBACK;
// Resolve creatorNickname: displayName for Discord tickets, senderLocal for email tickets
let creatorNickname;
if (freshTicket.gmailThreadId.startsWith('discord-')) {
const creatorUserId = freshTicket.gmailThreadId.split('-').pop();
try {
const creatorMember = await guild.members.fetch(creatorUserId);
creatorNickname = creatorMember.displayName;
} catch {
creatorNickname = freshTicket.senderEmail;
}
} else {
creatorNickname = getSenderLocal(freshTicket.senderEmail);
}
const creatorNickname = await resolveCreatorNickname(guild, freshTicket);
const renameInfo = await canRename(freshTicket);
if (renameInfo.ok) {
const newName = makeTicketName(
{ escalated: !!freshTicket.escalated, claimed: true },
freshTicket,
guild,
claimerEmoji,
creatorNickname
);
const state = freshTicket.escalated ? 'escalated-claimed' : 'claimed';
const newName = makeTicketName(state, freshTicket, creatorNickname, claimerEmoji);
try {
await enqueueRename(interaction.channel, newName);
} catch (e) {
@@ -377,10 +368,12 @@ async function handleClaim(interaction, ticket) {
freshTicket.claimerId = null;
freshTicket.staffChannelId = null;
const creatorNicknameUnclaim = await resolveCreatorNickname(guild, freshTicket);
const unclaimState = (freshTicket.escalationTier ?? 0) >= 1 ? 'escalated' : 'unclaimed';
const renameInfo = await canRename(freshTicket);
if (renameInfo.ok) {
try {
await enqueueRename(interaction.channel, `ticket-${freshTicket.ticketNumber}`);
await enqueueRename(interaction.channel, makeTicketName(unclaimState, freshTicket, creatorNicknameUnclaim));
} catch (e) {
console.error('Rename error (unclaim):', e);
}
@@ -607,6 +600,9 @@ async function handleTicketModal(interaction) {
const lastTicket = await Ticket.findOne().sort({ ticketNumber: -1 }).select('ticketNumber').lean();
const ticketNumber = (lastTicket?.ticketNumber || 0) + 1;
const creatorNicknameModal = interaction.member?.displayName || interaction.user.username;
const unclaimedName = toDiscordSafeName(`unclaimed-${creatorNicknameModal}-${ticketNumber}`);
let channel;
let parentCategoryIdForTicket = null;
if (useThread && CONFIG.DISCORD_THREAD_CHANNEL_ID) {
@@ -634,7 +630,7 @@ async function handleTicketModal(interaction) {
parentCategoryIdForTicket = parentId;
try {
channel = await guild.channels.create({
name: `ticket-${ticketNumber}`,
name: unclaimedName,
type: ChannelType.GuildText,
parent: parentId,
permissionOverwrites: [