Dead/stale removals (grep-confirmed no consumers):
- config: drop 9 unread CONFIG keys (ROLE_TO_PING_ID, SIGNATURE,
REMINDER_*, RENAME_LOG_CHANNEL_ID, SETTINGS_*); remove their
ALLOWED_CONFIG_KEYS entries and the orphaned settings-site UI fields
- configSchema: delete unreachable json/string_or_json validators
- models: drop unused ticketTag field
- gmail-poll: remove unused isPollSuspended export
- utils: remove dead htmlToTextWithBlocks/decodeHtmlEntities/BLOCK_TAG_REGEX
- internalApi: remove router._allowedKeys (test it served is gone)
- discord client: drop unused GuildPresences privileged intent
- broccolini-discord: remove dormant /api 503 gate (no /api routes)
Fixes:
- context-menu ticket create now uses makeTicketName('unclaimed', ...)
instead of the contract-violating ticket-<n> name
- drop write-only pending.userId from both close paths
Dedup / simplify:
- new services/transcript.js shares the transcript text/date/header
builders between the button and force-close paths (had drifted)
- resolveEscalationCategoryId() replaces 3 copies of the category logic
- ticketChannelOverwrites() shares the create-permission array between
the two interactive ticket-create paths
- finalizeBody() shares the email-cleanup tail in parseGmailMessage
- getTicketActionRow drops its never-passed options arg;
sendTicketNotificationEmail drops its always-null subjectLine arg
- hoist invariant guild lookup out of the auto-close/unclaim loops
- drop redundant lastActivity write (and now-dead updateTicketActivity)
- /help lists all current commands and the right-click apps
38 lines
1.5 KiB
JavaScript
38 lines
1.5 KiB
JavaScript
/**
|
|
* Shared transcript rendering for the two close paths
|
|
* (handlers/buttons.js runFinalClose and handlers/commands/close.js postTranscript).
|
|
* Pure formatting only — each caller owns its own posting / DB / email side effects.
|
|
*/
|
|
const { CONFIG } = require('../config');
|
|
|
|
/** Render the last 100 messages of a channel as a plaintext transcript. */
|
|
async function buildTranscriptText(channel, ticket) {
|
|
const messages = await channel.messages.fetch({ limit: 100 });
|
|
return `TRANSCRIPT: ${ticket.subject}\nUser: ${ticket.senderEmail}\n---\n` +
|
|
messages
|
|
.reverse()
|
|
.map(m => `[${m.createdAt.toLocaleString()}] ${m.author.tag}: ${m.cleanContent}`)
|
|
.join('\n');
|
|
}
|
|
|
|
/** Format a date for the transcript header (US locale, 12h, with time zone). */
|
|
function formatDateForTranscript(d) {
|
|
return new Date(d).toLocaleString('en-US', {
|
|
month: '2-digit', day: '2-digit', year: 'numeric',
|
|
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
|
hour12: true, timeZoneName: 'short'
|
|
});
|
|
}
|
|
|
|
/** Build the transcript-channel message body from DISCORD_TRANSCRIPT_MESSAGE. */
|
|
function renderTranscriptHeader(channelName, senderEmail, openedStr, closedStr) {
|
|
return CONFIG.DISCORD_TRANSCRIPT_MESSAGE
|
|
.replace(/\{channel_name\}/g, channelName)
|
|
.replace(/\{email\}/g, senderEmail || '')
|
|
.replace(/\{date_opened\}/g, openedStr)
|
|
.replace(/\{date_closed\}/g, closedStr)
|
|
+ `\n\nDate Opened: ${openedStr}\nDate Closed: ${closedStr}`;
|
|
}
|
|
|
|
module.exports = { buildTranscriptText, formatDateForTranscript, renderTranscriptHeader };
|