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:
156
config.js
156
config.js
@@ -30,88 +30,11 @@ if (!envPath) {
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_NOTIFICATION_THRESHOLDS = {
|
||||
// patternChecker - age-based (time since condition first became true)
|
||||
user_tickets: ['15m', '30m', '1h', '3h'],
|
||||
user_reopen: ['1h', '4h', '1d'],
|
||||
user_crossgame: ['1h', '1d'],
|
||||
game_surge: ['15m', '30m', '1h'],
|
||||
game_backlog: ['30m', '1h', '3h', '6h'],
|
||||
game_resolution: ['1d'],
|
||||
game_spike: ['15m', '30m'],
|
||||
tag_top: ['1h', '6h', '1d'],
|
||||
tag_escalation: ['1h', '6h', '1d'],
|
||||
untagged_closes: ['1h', '1d'],
|
||||
tag_game_corr: ['1d'],
|
||||
user_esc: ['1h', '6h', '1d'],
|
||||
game_esc_rate: ['1d'],
|
||||
rapid_t2_t3: ['3', '5', '10', '15', '20', '30', '50'], // count-based milestones, not time
|
||||
staff_no_close: ['1h', '3h'],
|
||||
staff_overloaded: ['1h', '3h', '6h'],
|
||||
staff_stale: ['1h', '3h'],
|
||||
staff_transfer_rate: ['1h', '1d'],
|
||||
staff_esc: ['1h', '6h', '1d'],
|
||||
staff_game_esc: ['1d'],
|
||||
game_tag_spike: ['1h', '6h'],
|
||||
overnight_gap: ['1d'],
|
||||
staff_always_esc: ['1d'],
|
||||
// surgeChecker - cooldown-escalating (repeat alerts spaced further apart)
|
||||
surge_tickets: ['10m', '30m', '1h', '2h', '3h'],
|
||||
surge_game: ['10m', '30m', '1h', '2h'],
|
||||
surge_stale: ['30m', '1h', '2h', '4h'],
|
||||
surge_needs_response: ['15m', '30m', '1h', '3h'],
|
||||
surge_unclaimed: ['15m', '30m', '1h', '2h', '4h'],
|
||||
surge_tier3_unclaimed: ['10m', '15m', '30m', '1h', '2h'],
|
||||
surge_no_staff: ['10m', '20m', '30m', '1h'],
|
||||
// staffNotifications - age-based per ticket (hours)
|
||||
unclaimed_reminder: ['1h', '2h', '4h', '8h', '1d'],
|
||||
// chatAlertChecker - cooldown-escalating
|
||||
chat_messages: ['15m', '30m', '1h', '3h'],
|
||||
chat_time: ['30m', '1h', '2h', '4h']
|
||||
};
|
||||
|
||||
function toInt(v, fallback) {
|
||||
const n = parseInt(v, 10);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
}
|
||||
|
||||
function parseThresholdString(str) {
|
||||
const value = String(str || '').trim();
|
||||
if (!value) return NaN;
|
||||
|
||||
// Integers without a unit are raw count milestones.
|
||||
if (/^\d+$/.test(value)) return parseInt(value, 10);
|
||||
|
||||
let totalMs = 0;
|
||||
const re = /(\d+)([mhd])/g;
|
||||
let match;
|
||||
let consumed = '';
|
||||
while ((match = re.exec(value)) !== null) {
|
||||
const amount = parseInt(match[1], 10);
|
||||
const unit = match[2];
|
||||
consumed += match[0];
|
||||
if (unit === 'm') totalMs += amount * 60 * 1000;
|
||||
else if (unit === 'h') totalMs += amount * 60 * 60 * 1000;
|
||||
else if (unit === 'd') totalMs += amount * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
if (!consumed || consumed !== value) return NaN;
|
||||
return totalMs;
|
||||
}
|
||||
|
||||
function parseNotificationThresholdsJson(raw) {
|
||||
if (!raw || !String(raw).trim()) return DEFAULT_NOTIFICATION_THRESHOLDS;
|
||||
try {
|
||||
const parsedJson = JSON.parse(raw);
|
||||
if (parsedJson && typeof parsedJson === 'object' && !Array.isArray(parsedJson)) {
|
||||
return parsedJson;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[config] Failed to parse NOTIFICATION_THRESHOLDS_JSON, using default:', err.message);
|
||||
}
|
||||
return DEFAULT_NOTIFICATION_THRESHOLDS;
|
||||
}
|
||||
|
||||
const CONFIG = {
|
||||
DISCORD_TOKEN: (process.env.DISCORD_TOKEN || process.env.DISCORD_BOT_TOKEN || '').trim(),
|
||||
DISCORD_GUILD_ID: process.env.DISCORD_GUILD_ID || null,
|
||||
@@ -181,8 +104,6 @@ const CONFIG = {
|
||||
PRIORITY_HIGH_EMOJI: process.env.PRIORITY_HIGH_EMOJI || '🔴',
|
||||
PRIORITY_MEDIUM_EMOJI: process.env.PRIORITY_MEDIUM_EMOJI || '🟡',
|
||||
PRIORITY_LOW_EMOJI: process.env.PRIORITY_LOW_EMOJI || '🟢',
|
||||
CLAIM_TIMEOUT_ENABLED: process.env.CLAIM_TIMEOUT_ENABLED === 'true',
|
||||
CLAIM_TIMEOUT_HOURS: toInt(process.env.CLAIM_TIMEOUT_HOURS, 48),
|
||||
AUTO_UNCLAIM_ENABLED: process.env.AUTO_UNCLAIM_ENABLED === 'true',
|
||||
AUTO_UNCLAIM_AFTER_HOURS: toInt(process.env.AUTO_UNCLAIM_AFTER_HOURS, 24),
|
||||
ALLOW_CLAIM_OVERWRITE: process.env.ALLOW_CLAIM_OVERWRITE === 'true',
|
||||
@@ -199,25 +120,7 @@ const CONFIG = {
|
||||
EMBED_COLOR_CLAIMED: toInt(process.env.EMBED_COLOR_CLAIMED, 0xFFFF00),
|
||||
EMBED_COLOR_ESCALATED: toInt(process.env.EMBED_COLOR_ESCALATED, 0xFF6600),
|
||||
EMBED_COLOR_INFO: toInt(process.env.EMBED_COLOR_INFO, 0x1e2124),
|
||||
STAFF_CATEGORIES: new Map(), // deprecated – kept for staffChannel.js compat
|
||||
STAFF_EMOJIS: (() => {
|
||||
const raw = process.env.STAFF_EMOJIS;
|
||||
const map = new Map();
|
||||
if (!raw || !String(raw).trim()) return map;
|
||||
for (const part of String(raw).split(',')) {
|
||||
const seg = part.trim();
|
||||
if (!seg) continue;
|
||||
const idx = seg.indexOf(':');
|
||||
if (idx === -1) continue;
|
||||
const userId = seg.slice(0, idx).trim();
|
||||
const emoji = seg.slice(idx + 1).trim();
|
||||
if (userId && emoji) map.set(userId, emoji);
|
||||
}
|
||||
return map;
|
||||
})(),
|
||||
CLAIMER_EMOJI_FALLBACK: process.env.CLAIMER_EMOJI_FALLBACK || '🎫',
|
||||
ADMIN_ID: process.env.ADMIN_ID || null,
|
||||
STAFF_NOTIFICATION_CATEGORY_ID: process.env.STAFF_NOTIFICATION_CATEGORY_ID || null,
|
||||
FORCE_CLOSE_TIMER: toInt(process.env.FORCE_CLOSE_TIMER_SECONDS, 60),
|
||||
GMAIL_POLL_INTERVAL_MS: toInt(process.env.GMAIL_POLL_INTERVAL_SECONDS, 30) * 1000,
|
||||
GMAIL_LOG_CHANNEL_ID: process.env.GMAIL_LOG_CHANNEL_ID || null,
|
||||
@@ -225,42 +128,6 @@ const CONFIG = {
|
||||
RENAME_LOG_CHANNEL_ID: process.env.RENAME_LOG_CHANNEL_ID || null,
|
||||
SECURITY_LOG_CHANNEL_ID: process.env.SECURITY_LOG_CHANNEL_ID || null,
|
||||
SYSTEM_LOG_CHANNEL_ID: process.env.SYSTEM_LOG_CHANNEL_ID || null,
|
||||
USER_PATTERNS_CHANNEL_ID: process.env.USER_PATTERNS_CHANNEL_ID || null,
|
||||
GAME_PATTERNS_CHANNEL_ID: process.env.GAME_PATTERNS_CHANNEL_ID || null,
|
||||
TAG_PATTERNS_CHANNEL_ID: process.env.TAG_PATTERNS_CHANNEL_ID || null,
|
||||
ESCALATION_PATTERNS_CHANNEL_ID: process.env.ESCALATION_PATTERNS_CHANNEL_ID || null,
|
||||
STAFF_PATTERNS_CHANNEL_ID: process.env.STAFF_PATTERNS_CHANNEL_ID || null,
|
||||
COMBINED_PATTERNS_CHANNEL_ID: process.env.COMBINED_PATTERNS_CHANNEL_ID || null,
|
||||
PATTERN_USER_TICKET_THRESHOLD: toInt(process.env.PATTERN_USER_TICKET_THRESHOLD, 3),
|
||||
PATTERN_GAME_TICKET_THRESHOLD: toInt(process.env.PATTERN_GAME_TICKET_THRESHOLD, 10),
|
||||
PATTERN_STAFF_STALE_PING_THRESHOLD: toInt(process.env.PATTERN_STAFF_STALE_PING_THRESHOLD, 5),
|
||||
PATTERN_ESCALATION_THRESHOLD: toInt(process.env.PATTERN_ESCALATION_THRESHOLD, 3),
|
||||
PATTERN_RAPID_CLOSE_SECONDS: toInt(process.env.PATTERN_RAPID_CLOSE_SECONDS, 120),
|
||||
PATTERN_UNCLAIMED_HOURS: toInt(process.env.PATTERN_UNCLAIMED_HOURS, 4),
|
||||
PATTERN_CHECK_INTERVAL_MINUTES: toInt(process.env.PATTERN_CHECK_INTERVAL_MINUTES, 30),
|
||||
ALL_STAFF_CHANNEL_ID: process.env.ALL_STAFF_CHANNEL_ID || null,
|
||||
ALL_STAFF_CHAT_ALERT_CHANNEL_ID: process.env.ALL_STAFF_CHAT_ALERT_CHANNEL_ID || null,
|
||||
SURGE_ROLE_ID: process.env.SURGE_ROLE_ID || null,
|
||||
SURGE_TICKET_COUNT: toInt(process.env.SURGE_TICKET_COUNT, 10),
|
||||
SURGE_TICKET_WINDOW_MINUTES: toInt(process.env.SURGE_TICKET_WINDOW_MINUTES, 30),
|
||||
SURGE_GAME_TICKET_COUNT: toInt(process.env.SURGE_GAME_TICKET_COUNT, 5),
|
||||
SURGE_GAME_TICKET_WINDOW_MINUTES: toInt(process.env.SURGE_GAME_TICKET_WINDOW_MINUTES, 30),
|
||||
SURGE_STALE_COUNT: toInt(process.env.SURGE_STALE_COUNT, 8),
|
||||
SURGE_STALE_HOURS: toInt(process.env.SURGE_STALE_HOURS, 2),
|
||||
SURGE_NEEDS_RESPONSE_COUNT: toInt(process.env.SURGE_NEEDS_RESPONSE_COUNT, 5),
|
||||
SURGE_NEEDS_RESPONSE_HOURS: toInt(process.env.SURGE_NEEDS_RESPONSE_HOURS, 1),
|
||||
SURGE_UNCLAIMED_COUNT: toInt(process.env.SURGE_UNCLAIMED_COUNT, 5),
|
||||
SURGE_UNCLAIMED_MINUTES: toInt(process.env.SURGE_UNCLAIMED_MINUTES, 30),
|
||||
SURGE_TIER3_UNCLAIMED_MINUTES: toInt(process.env.SURGE_TIER3_UNCLAIMED_MINUTES, 15),
|
||||
SURGE_COOLDOWN_MINUTES: toInt(process.env.SURGE_COOLDOWN_MINUTES, 60),
|
||||
CHAT_ALERT_CHANNEL_IDS: (process.env.CHAT_ALERT_CHANNEL_IDS || '').split(',').filter(Boolean),
|
||||
CHAT_ALERT_MESSAGE_COUNT: toInt(process.env.CHAT_ALERT_MESSAGE_COUNT, 5),
|
||||
CHAT_ALERT_HOURS_WITHOUT_RESPONSE: toInt(process.env.CHAT_ALERT_HOURS_WITHOUT_RESPONSE, 2),
|
||||
CHAT_ALERT_COOLDOWN_MINUTES: toInt(process.env.CHAT_ALERT_COOLDOWN_MINUTES, 60),
|
||||
STAFF_IDS: (process.env.STAFF_IDS || '').split(',').map(s => s.trim()).filter(Boolean),
|
||||
SURGE_NO_STAFF_COOLDOWN_MINUTES: toInt(process.env.SURGE_NO_STAFF_COOLDOWN_MINUTES, 30),
|
||||
SURGE_NO_STAFF_OPEN_TICKET_THRESHOLD: toInt(process.env.SURGE_NO_STAFF_OPEN_TICKET_THRESHOLD, 3),
|
||||
STAFF_DND_COUNTS_AS_AVAILABLE: process.env.STAFF_DND_COUNTS_AS_AVAILABLE === 'true',
|
||||
STAFF_THREAD_ENABLED: process.env.STAFF_THREAD_ENABLED === 'true',
|
||||
STAFF_THREAD_NAME: process.env.STAFF_THREAD_NAME || 'Staff Discussion',
|
||||
STAFF_THREAD_AUTO_ADD_ROLE: process.env.STAFF_THREAD_AUTO_ADD_ROLE === 'true',
|
||||
@@ -273,28 +140,9 @@ const CONFIG = {
|
||||
SETTINGS_ADMIN_PASSWORD: process.env.SETTINGS_ADMIN_PASSWORD || null,
|
||||
SETTINGS_DOMAIN: process.env.SETTINGS_DOMAIN || 'tickets.indifferentketchup.com',
|
||||
INTERNAL_API_PORT: toInt(process.env.INTERNAL_API_PORT, 12753),
|
||||
INTERNAL_API_SECRET: process.env.INTERNAL_API_SECRET || null,
|
||||
NOTIFICATION_THRESHOLDS: parseNotificationThresholdsJson(process.env.NOTIFICATION_THRESHOLDS_JSON),
|
||||
UNCLAIMED_REMINDER_THRESHOLDS: (process.env.UNCLAIMED_REMINDER_THRESHOLDS || '1,2,4')
|
||||
.split(',')
|
||||
.map(s => parseInt(s.trim(), 10))
|
||||
.filter(n => !isNaN(n) && n > 0)
|
||||
INTERNAL_API_SECRET: process.env.INTERNAL_API_SECRET || null
|
||||
};
|
||||
|
||||
/** Ticket category tags for /tag set – [emoji] [label] in dropdown; priority emoji always first in channel name, then tag emoji. */
|
||||
const TICKET_TAGS = [
|
||||
{ value: 'server-down', emoji: '⬇️', name: 'Server Down' },
|
||||
{ value: 'stuck-restarting', emoji: '⏳', name: 'Stuck Restarting' },
|
||||
{ value: 'cant-connect', emoji: '📵', name: "Can't Connect" },
|
||||
{ value: 'server-lag', emoji: '🐌', name: 'Server Lag' },
|
||||
{ value: 'billing', emoji: '💳', name: 'Billing' },
|
||||
{ value: 'refund-request', emoji: '💸', name: 'Refund Request' },
|
||||
{ value: 'mod-help', emoji: '🔧', name: 'Mod Help' },
|
||||
{ value: 'backup-restore', emoji: '💾', name: 'Backup Restore' },
|
||||
{ value: 'world-save', emoji: '🌍', name: 'World / Save' },
|
||||
{ value: 'server-config', emoji: '⚙️', name: 'Server Config' }
|
||||
];
|
||||
|
||||
const GAME_NAMES = (CONFIG.GAME_LIST || '')
|
||||
.split(',')
|
||||
.map(g => g.trim())
|
||||
@@ -346,8 +194,6 @@ const GAME_NAME_TO_KEY = {
|
||||
|
||||
module.exports = {
|
||||
CONFIG,
|
||||
parseThresholdString,
|
||||
TICKET_TAGS,
|
||||
GAME_NAMES,
|
||||
GAME_ALIASES,
|
||||
GAME_NAME_TO_KEY
|
||||
|
||||
Reference in New Issue
Block a user