strip: remove pattern/surge/chat alert monitoring + unused commands

- delete services/{patternChecker,patternStore,surgeChecker,chatAlertChecker,staffNotifications,staffChannel,notificationRegistry,notificationEnabled,staffPresence}.js
- remove /notification, /staffnotification, /tag, /priority
- /escalate: drop action param, always unclaim
- purge PATTERN_*, SURGE_*, CHAT_ALERT_*, STAFF_* env vars from config + .env.example
- drop StaffNotification model
- ~2500 LOC removed
- settings-site /internal/notifications/* endpoints gone (UI will 404 until trimmed)
This commit is contained in:
2026-04-21 15:57:18 +00:00
parent 298cf13d5c
commit 636348d824
27 changed files with 3335 additions and 2532 deletions

View File

@@ -11,9 +11,9 @@ const {
PermissionFlagsBits
} = require('discord.js');
const { mongoose } = require('../db-connection');
const { CONFIG, TICKET_TAGS } = require('../config');
const { getPriorityEmoji, getPriorityColor, replaceVariables, escapeRegex } = require('../utils');
const { makeTicketName, resolveCreatorNickname, getSenderLocal, toDiscordSafeName, getOrCreateTicketCategory, createDiscordTicketAsThread, checkTicketCreationRateLimit } = require('../services/tickets');
const { CONFIG } = require('../config');
const { getPriorityEmoji, replaceVariables, escapeRegex } = require('../utils');
const { makeTicketName, resolveCreatorNickname, getOrCreateTicketCategory, createDiscordTicketAsThread, checkTicketCreationRateLimit } = require('../services/tickets');
const { sendTicketNotificationEmail } = require('../services/gmail');
const { getTicketActionRow } = require('../utils/ticketComponents');
const { getEmailRouting } = require('../services/guildSettings');
@@ -24,12 +24,10 @@ const { logTicketEvent, logSecurity, logError } = require('../services/debugLog'
const { handleAccountInfoCommand } = require('./accountinfo');
const { handleSetupCommand } = require('./setup');
const { pendingCloses } = require('./pendingCloses');
const { increment } = require('../services/patternStore');
const Ticket = mongoose.model('Ticket');
const Tag = mongoose.model('Tag');
const User = mongoose.model('User');
const StaffNotification = mongoose.model('StaffNotification');
/**
* True if member has the support role (ROLE_ID_TO_PING) or any ADDITIONAL_STAFF_ROLES.
@@ -74,17 +72,11 @@ async function runEscalation(interaction, ticket, nextTier, reason) {
// Clear claim on escalation
await Ticket.updateOne(
{ gmailThreadId: ticket.gmailThreadId },
{ $set: { escalated: true, escalationTier: nextTier, claimedBy: null, claimerId: null, unclaimedRemindersSent: [] } }
{ $set: { escalated: true, escalationTier: nextTier, claimedBy: null, claimerId: null } }
);
ticket.escalated = true;
ticket.escalationTier = nextTier;
ticket.claimedBy = null;
increment('escalations', ticket.game || 'unknown', 'today');
increment('escalations', ticket.game || 'unknown', 'week');
increment('user_escalations', ticket.senderEmail, 'week');
increment('staff_escalations', interaction.user.id, 'today');
increment('staff_escalations', interaction.user.id, 'week');
if (ticket.game) increment(`staff_game_escalations:${interaction.user.id}`, ticket.game, 'week');
const creatorNickname = await resolveCreatorNickname(interaction.guild, ticket);
const newName = makeTicketName('escalated', ticket, creatorNickname);
@@ -265,12 +257,11 @@ async function handleCommand(interaction) {
return;
}
// /escalate (tier 2 or 3 via level; works for both email and Discord)
// /escalate (tier 2 or 3 via level; works for both email and Discord). Always unclaims on escalate.
if (interaction.commandName === 'escalate') {
const reason = null;
const level = interaction.options.getString('level');
const nextTier = level === '3' ? 2 : 1;
const action = interaction.options.getString('action');
const ticket = await Ticket.findOne({ discordThreadId: interaction.channel.id }).lean();
if (!ticket) {
@@ -301,12 +292,6 @@ async function handleCommand(interaction) {
try {
await interaction.deferReply();
await runEscalation(interaction, ticket, nextTier, reason);
if (action === 'unclaim') {
await Ticket.updateOne(
{ gmailThreadId: ticket.gmailThreadId },
{ $set: { claimedBy: null, claimerId: null } }
);
}
} catch (err) {
console.error('Escalate error:', err);
await interaction.editReply({ content: 'Failed to escalate this ticket.' }).catch(() =>
@@ -315,83 +300,6 @@ async function handleCommand(interaction) {
}
}
// /notification set | /notification add
if (interaction.commandName === 'notification') {
const sub = interaction.options.getSubcommand();
if (sub === 'set') {
const hours = interaction.options.getInteger('hours');
try {
await StaffNotification.findOneAndUpdate(
{ userId: interaction.user.id },
{ $set: { cooldownHours: hours, updatedAt: new Date() } },
{ upsert: true }
);
return interaction.reply({ content: `Notification cooldown set to ${hours} hour(s).`, ephemeral: true });
} catch (err) {
console.error('notification set error:', err);
return interaction.reply({ content: 'Failed to update notification setting.', ephemeral: true }).catch(() => {});
}
}
if (sub === 'add') {
if (!CONFIG.STAFF_NOTIFICATION_CATEGORY_ID) {
return interaction.reply({ content: 'STAFF_NOTIFICATION_CATEGORY_ID is not configured.', ephemeral: true });
}
const member = interaction.options.getMember('member');
if (!member) {
return interaction.reply({ content: 'Could not resolve that member.', ephemeral: true });
}
const displayName = member.displayName;
const emoji = CONFIG.STAFF_EMOJIS.get(member.id) || '';
const chanName = toDiscordSafeName(`${displayName}${emoji}`);
try {
const newChannel = await interaction.guild.channels.create({
name: chanName,
type: ChannelType.GuildText,
parent: CONFIG.STAFF_NOTIFICATION_CATEGORY_ID,
permissionOverwrites: [
{ id: interaction.guild.id, deny: [PermissionFlagsBits.ViewChannel] },
{ id: member.id, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages, PermissionFlagsBits.ReadMessageHistory] },
...(CONFIG.ROLE_ID_TO_PING ? [{ id: CONFIG.ROLE_ID_TO_PING, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages, PermissionFlagsBits.ReadMessageHistory] }] : [])
]
});
await StaffNotification.findOneAndUpdate(
{ userId: member.id },
{ $set: { channelId: newChannel.id, guildId: interaction.guild.id, updatedAt: new Date() } },
{ upsert: true }
);
return interaction.reply({ content: `Notification channel created: ${newChannel}`, ephemeral: true });
} catch (err) {
console.error('notification add error:', err);
return interaction.reply({ content: 'Failed to create notification channel.', ephemeral: true }).catch(() => {});
}
}
return;
}
// /staffnotification (admin only)
if (interaction.commandName === 'staffnotification') {
if (interaction.user.id !== CONFIG.ADMIN_ID) {
logSecurity('Unauthorized command attempt', interaction.user, interaction.commandName).catch(() => {});
return interaction.reply({ content: 'This command is restricted to the bot admin.', ephemeral: true });
}
const member = interaction.options.getMember('member');
const hours = interaction.options.getInteger('hours');
if (!member) {
return interaction.reply({ content: 'Could not resolve that member.', ephemeral: true });
}
try {
await StaffNotification.findOneAndUpdate(
{ userId: member.id },
{ $set: { cooldownHours: hours, updatedAt: new Date() } },
{ upsert: true }
);
return interaction.reply({ content: `Notification cooldown for ${member.displayName} set to ${hours} hour(s).`, ephemeral: true });
} catch (err) {
console.error('staffnotification error:', err);
return interaction.reply({ content: 'Failed to update notification setting.', ephemeral: true }).catch(() => {});
}
}
if (interaction.commandName === 'notifydm') {
try {
const setting = interaction.options.getString('setting') === 'on';
@@ -723,32 +631,6 @@ async function handleCommand(interaction) {
}
}
// /tag ticket category dropdown only
if (interaction.commandName === 'tag') {
trackInteraction('commands', 'tag', interaction.user.tag);
const categoryValue = interaction.options.getString('category');
const ticket = await Ticket.findOne({ discordThreadId: interaction.channel.id }).lean();
if (!ticket) {
return interaction.reply({ content: 'This channel is not linked to a ticket.', ephemeral: true });
}
try {
await Ticket.updateOne(
{ gmailThreadId: ticket.gmailThreadId },
{ $set: { ticketTag: categoryValue } }
);
const tagEntry = (TICKET_TAGS || []).find(t => t.value === categoryValue);
const emoji = tagEntry ? tagEntry.emoji : '';
const channelMessage = `Your ticket has been categorized as ${emoji} **${tagEntry ? tagEntry.name : categoryValue}** ${emoji}.`;
await interaction.reply(channelMessage);
increment('tag_usage', categoryValue, 'today');
increment('tag_usage', categoryValue, 'week');
if (ticket.game) increment(`tag_game:${categoryValue}`, ticket.game, 'week');
} catch (err) {
trackError('tag-command', err, interaction);
await interaction.reply({ content: 'Failed to set ticket category.', ephemeral: true });
}
}
// /response saved response tags (send, create, edit, delete, list)
if (interaction.commandName === 'response') {
trackInteraction('commands', 'response', interaction.user.tag);
@@ -936,14 +818,14 @@ async function handleCommand(interaction) {
},
{
name: 'Ticket Management',
value: '`/transfer @staff` - Transfer ticket to another staff member\n`/move #category` - Move ticket to another category\n`/force-close` - Force close ticket without confirmation\n`/topic <text>` - Set ticket topic/description\n`/priority <level>` - Set ticket priority\n`/accountinfo email` - Look up website account by email\n`/accountinfo discord @user` - Look up website account by Discord user'
value: '`/transfer @staff` - Transfer ticket to another staff member\n`/move #category` - Move ticket to another category\n`/force-close` - Force close ticket without confirmation\n`/topic <text>` - Set ticket topic/description\n`/accountinfo email` - Look up website account by email\n`/accountinfo discord @user` - Look up website account by Discord user'
},
{
name: 'Tags & Responses',
value: '`/tag` - Set ticket category (dropdown)\n`/response send <name>` - Send saved response\n`/response create|edit|delete|list` - Manage saved responses'
name: 'Saved Responses',
value: '`/response send <name>` - Send saved response\n`/response create|edit|delete|list` - Manage saved responses'
},
{
name: 'Variables (for tags)',
name: 'Variables (for responses)',
value: '`{ticket.user}`, `{ticket.email}`, `{ticket.number}`, `{ticket.subject}`, `{staff.name}`, `{server.name}`, `{date}`, `{time}`'
},
{
@@ -960,63 +842,6 @@ async function handleCommand(interaction) {
await interaction.reply({ embeds: [embed], ephemeral: true });
}
// /priority
if (interaction.commandName === 'priority') {
const level = interaction.options.getString('level');
const ticket = await Ticket.findOne({ discordThreadId: interaction.channel.id }).lean();
if (!ticket) {
return interaction.reply({ content: 'This channel is not linked to a ticket.', ephemeral: true });
}
const priorityOrder = ['low', 'normal', 'medium', 'high'];
const oldIdx = priorityOrder.indexOf((ticket.priority || 'normal').toLowerCase());
const newIdx = priorityOrder.indexOf(level.toLowerCase());
const emoji = getPriorityEmoji(level);
const levelLabel = level.charAt(0).toUpperCase() + level.slice(1).toLowerCase();
let channelMessage;
if (level === 'normal') {
channelMessage = 'Your ticket priority has returned to Normal.';
} else if (newIdx > oldIdx) {
channelMessage = `Your ticket has been upgraded to ${emoji} **${levelLabel}** ${emoji}.`;
} else if (newIdx < oldIdx) {
channelMessage = `Your ticket has been downgraded to ${emoji} **${levelLabel}** ${emoji}.`;
} else {
channelMessage = `Priority set to ${emoji} **${levelLabel}** ${emoji}.`;
}
try {
await Ticket.updateOne(
{ gmailThreadId: ticket.gmailThreadId },
{ $set: { priority: level } }
);
const priorityTitle =
newIdx === oldIdx
? 'Priority Set'
: `Priority ${newIdx > oldIdx ? 'Upgraded' : 'Downgraded'}${levelLabel}`;
const priorityEmbed = new EmbedBuilder()
.setTitle(priorityTitle)
.setDescription(channelMessage)
.setColor(getPriorityColor(level))
.setFooter({ text: interaction.member?.displayName || interaction.user.username });
await interaction.reply({ embeds: [priorityEmbed] });
if (level === 'high' && ticket.gmailThreadId && !ticket.gmailThreadId.startsWith('discord-')) {
await sendTicketNotificationEmail(
ticket,
`Priority updated: ${levelLabel}`,
channelMessage,
interaction.member?.displayName || interaction.user.username
);
}
} catch (err) {
console.error('Priority update error:', err);
await interaction.reply({ content: 'Failed to update priority.', ephemeral: true });
}
}
// /panel
if (interaction.commandName === 'panel') {
const channel = interaction.options.getChannel('channel');