huge changes

This commit is contained in:
indifferentketchup
2026-04-07 01:43:06 -05:00
parent ca63ecbcfd
commit 69c247ed1b
37 changed files with 3468 additions and 169 deletions

View File

@@ -8,7 +8,7 @@ const {
ButtonStyle,
EmbedBuilder
} = require('discord.js');
const { mongoose } = require('./db-connection');
const { mongoose, withRetry } = require('./db-connection');
const { CONFIG, GAME_NAME_TO_KEY } = require('./config');
const {
getCleanBody,
@@ -16,23 +16,38 @@ const {
stripEmailQuotes,
stripMobileFooter,
detectGame,
getFormattedDate
getFormattedDate,
truncateEmbedField,
enforceEmbedLimit
} = require('./utils');
const { getGmailClient } = require('./services/gmail');
const { getNextTicketNumber, checkTicketLimits, getOrCreateTicketCategory, createEmailTicketAsThread, toDiscordSafeName, getSenderLocal } = require('./services/tickets');
const { getEmailRouting } = require('./services/guildSettings');
const { logError } = require('./services/debugLog');
const { logError, logGmail } = require('./services/debugLog');
const { increment } = require('./services/patternStore');
const Ticket = mongoose.model('Ticket');
const Transcript = mongoose.model('Transcript');
let isPolling = false;
let authErrorNotified = false;
let pollCount = 0, totalProcessed = 0, totalSkipped = 0, totalErrors = 0;
/**
* Poll Gmail for unread primary-inbox messages and route them to Discord.
* @param {import('discord.js').Client} client
*/
async function poll(client) {
console.log('Running poll()...');
if (isPolling) return;
isPolling = true;
try {
pollCount++;
if (pollCount % 10 === 0) {
logGmail('Poll summary', `polls: ${pollCount}, processed: ${totalProcessed}, skipped: ${totalSkipped}, errors: ${totalErrors}`, null, null).catch(() => {});
pollCount = 0; totalProcessed = 0; totalSkipped = 0; totalErrors = 0;
}
console.log('Running poll()...');
try {
const gmail = getGmailClient();
const list = await gmail.users.messages.list({
userId: 'me',
@@ -68,6 +83,7 @@ async function poll(client) {
email.data.payload.headers.find(h => h.name === 'From')
?.value || '';
if (from.toLowerCase().includes(CONFIG.MY_EMAIL)) {
totalSkipped++;
await gmail.users.messages.batchModify({
userId: 'me',
requestBody: {
@@ -146,6 +162,7 @@ async function poll(client) {
// Check ticket limits before creating
const limitCheck = await checkTicketLimits(sEmail);
if (!limitCheck.ok) {
totalSkipped++;
console.log(`Ticket limit reached for ${sEmail}: ${limitCheck.reason}`);
await gmail.users.messages.batchModify({
userId: 'me',
@@ -227,20 +244,29 @@ async function poll(client) {
.setColor(CONFIG.EMBED_COLOR_INFO)
.addFields({
name: 'Ticket Info',
value:
value: truncateEmbedField(
`**Name:** ${sName}\n` +
`**Email:** ${sEmail}\n` +
`**Date:** ${getFormattedDate()}\n` +
`**Game:** ${detectedGame}\n` +
`**Subject:** ${subject || 'No subject'}`
`**Subject:** ${subject || 'No subject'}`)
});
await ticketChan.send({
enforceEmbedLimit([welcomeEmbed, ticketInfoEmbed]);
const welcomeMsg = await ticketChan.send({
content: `<@&${CONFIG.ROLE_ID_TO_PING}>`,
embeds: [welcomeEmbed, ticketInfoEmbed],
components: [buttons]
});
const { createStaffThread } = require('./services/staffThread');
await createStaffThread(ticketChan, client).catch(() => {});
if (CONFIG.PIN_INITIAL_MESSAGE_ENABLED && welcomeMsg) {
const { pinMessage } = require('./services/pinMessage');
await pinMessage(welcomeMsg, client).catch(() => {});
}
// On reopen, link previous transcripts
if (isReopened) {
try {
@@ -292,7 +318,7 @@ async function poll(client) {
const now = new Date();
const defaultPriority = CONFIG.PRIORITY_ENABLED ? CONFIG.DEFAULT_PRIORITY : 'normal';
await Ticket.findOneAndUpdate(
await withRetry(() => Ticket.findOneAndUpdate(
{ gmailThreadId: email.data.threadId },
{
$set: {
@@ -308,7 +334,15 @@ async function poll(client) {
}
},
{ upsert: true, new: true }
);
));
totalProcessed++;
logGmail(subject, sEmail, number, detectedGame).catch(() => {});
increment('user_tickets', sEmail, 'today');
increment('user_tickets', sEmail, 'week');
if (detectedGame) {
increment('game_tickets', detectedGame, 'today');
increment('game_tickets', detectedGame, 'week');
}
}
console.log('Archiving/reading Gmail message', msgRef.id);
await gmail.users.messages.batchModify({
@@ -319,10 +353,32 @@ async function poll(client) {
}
});
}
authErrorNotified = false;
} catch (e) {
const isAuthError =
(e.message && (
e.message.includes('invalid_grant') ||
e.message.includes('unauthorized') ||
e.message.includes('Invalid Credentials')
)) ||
e.status === 401 ||
e.code === 401;
if (isAuthError) {
logError('Gmail OAuth', { message: 'Gmail OAuth token invalid or expired. Re-authentication required.', stack: e.stack || e.message || String(e) }, null, client);
if (CONFIG.ADMIN_ID && !authErrorNotified) {
authErrorNotified = true;
client.users.fetch(CONFIG.ADMIN_ID).then(u => u.send('Gmail OAuth token invalid or expired. Re-authentication required.')).catch(() => {});
}
}
totalErrors++;
console.error('POLL ERROR:', e);
logError('Gmail poll', e, null, client);
}
} finally {
isPolling = false;
}
}
module.exports = { poll };