Files
broccolini-bot/models.js
indifferentketchup 2fab3b97bf Remove dead/stale code, dedup close+escalation paths
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
2026-06-02 19:59:14 +00:00

64 lines
2.3 KiB
JavaScript

var mongoose = require('mongoose');
// ===== Broccolini Bot Models =====
const ticketSchema = new mongoose.Schema({
gmailThreadId: { type: String, required: true, unique: true, index: true },
discordThreadId: String,
senderEmail: { type: String, required: true },
subject: String,
createdAt: { type: Date, default: Date.now },
status: { type: String, default: 'open', enum: ['open', 'closed'] },
transcriptMessageId: String,
claimedBy: String,
escalated: { type: Boolean, default: false },
escalationTier: { type: Number, default: 0 },
ticketNumber: Number,
priority: { type: String, default: 'normal', enum: ['low', 'normal', 'medium', 'high'] },
lastActivity: Date,
welcomeMessageId: String,
claimerId: String,
creatorId: String,
parentCategoryId: String,
pendingDelete: { type: Boolean, default: false }
});
ticketSchema.index({ status: 1, lastActivity: 1 });
ticketSchema.index({ senderEmail: 1, status: 1 });
ticketSchema.index({ discordThreadId: 1 });
mongoose.model('Ticket', ticketSchema);
mongoose.model('TicketCounter', new mongoose.Schema({
senderLocal: { type: String, required: true, unique: true },
counter: { type: Number, default: 1 }
}));
mongoose.model('Transcript', new mongoose.Schema({
gmailThreadId: { type: String, required: true },
transcriptMessageId: String,
createdAt: { type: Date, default: Date.now }
}));
mongoose.model('Tag', new mongoose.Schema({
name: { type: String, required: true, unique: true },
content: { type: String, required: true },
createdAt: { type: Date, default: Date.now },
createdBy: String,
useCount: { type: Number, default: 0 }
}));
mongoose.model('StaffSettings', new mongoose.Schema({
userId: { type: String, required: true, unique: true },
guildId: { type: String, required: true },
notifyDm: { type: Boolean, default: false },
updatedAt: { type: Date, default: Date.now }
}));
mongoose.model('StaffSignature', new mongoose.Schema({
userId: { type: String, required: true, unique: true },
guildId: { type: String, required: true },
valediction: { type: String, default: '' },
displayName: { type: String, default: '' },
tagline: { type: String, default: '' },
updatedAt: { type: Date, default: Date.now }
}));