audit week 1: creator ID tracking, channel-queue migration, deprecation cleanup
QUAL-006 store ticket.creatorId on creation; legacy split-pop returned the
message ID for discord-msg-* tickets, breaking transcript DM, close
log, and channel rename for context-menu-created tickets. Adds the
field to the Ticket schema and writes a one-shot backfill script
(scripts/backfill-creatorId.js, dry-run by default).
QUEUE-001 add enqueueOverwrite + enqueueTopic to services/channelQueue.js
(chain on renameChains alongside enqueueMove). Migrate handleAdd /
handleRemove / handleMove / handleTopic so permissionOverwrites,
setParent, and setTopic no longer race pending renames or sends.
handleMove now uses the existing enqueueMove. Initial overwrites in
handleTicketModal stay inline; channel doesn't exist yet so no race.
DISCORD-001 replace ephemeral: true with flags: MessageFlags.Ephemeral across
broccolini-discord.js, handlers/sharedHelpers.js, handlers/buttons.js,
handlers/commands.js. runDeferred opts now take { flags } directly.
SEC-003 /gmailpoll min interval is 30s. Drop the 5s/10s slash-command
choices and clamp Math.max(30000, ms) in handleGmailPoll for
defense in depth.
QUAL-001 upgrade silent .catch(() => {}) on the lastActivity updateOne in
handlers/messages.js to log via logError, so transient Mongo errors
surface in the debug channel instead of disappearing.
QUAL-002 drop await from logError/logWarn calls in services/staffThread.js
and services/pinMessage.js — fire-and-forget per CLAUDE.md hard rule.
QUAL-003 wrap stray setTimeouts (handleConfirmCloseRequest force-close timer,
runFinalClose channel-delete + overflow-cleanup, checkAutoClose
delete-after-email) in trackTimeout via lazy require so they clear
on shutdown.
This commit is contained in:
@@ -51,7 +51,12 @@ function toDiscordSafeName(str) {
|
||||
*/
|
||||
async function resolveCreatorNickname(guild, ticket) {
|
||||
if (ticket.gmailThreadId.startsWith('discord-')) {
|
||||
const creatorUserId = ticket.gmailThreadId.split('-').pop();
|
||||
// Prefer ticket.creatorId (stored on creation). Legacy fallback parses the
|
||||
// tail segment, which is correct for discord-${ts}-${userId} but returns
|
||||
// the message ID for discord-msg-${ts}-${msgId} — skip the parse for those.
|
||||
const creatorUserId = ticket.creatorId
|
||||
|| (ticket.gmailThreadId.startsWith('discord-msg-') ? null : ticket.gmailThreadId.split('-').pop());
|
||||
if (!creatorUserId) return getSenderLocal(ticket.senderEmail);
|
||||
try {
|
||||
const member = await guild.members.fetch(creatorUserId);
|
||||
return member.displayName;
|
||||
@@ -305,14 +310,16 @@ async function checkAutoClose(client, sendTicketClosedEmail) {
|
||||
|
||||
await sendTicketClosedEmail(ticket, 'Auto-Close System', null);
|
||||
|
||||
setTimeout(() => {
|
||||
// Lazy require — broccolini-discord re-exports trackTimeout; cycle-safe.
|
||||
const { trackTimeout } = require('../broccolini-discord');
|
||||
trackTimeout(setTimeout(() => {
|
||||
enqueueDelete(channel).then(() => {
|
||||
withRetry(() => Ticket.updateOne(
|
||||
{ gmailThreadId: ticket.gmailThreadId },
|
||||
{ $unset: { pendingDelete: '' } }
|
||||
)).catch(() => {});
|
||||
}).catch(() => {});
|
||||
}, 5000);
|
||||
}, 5000));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Auto-close error for ticket ${ticket.gmailThreadId}:`, error);
|
||||
|
||||
Reference in New Issue
Block a user