This commit is contained in:
2026-04-21 14:31:59 +00:00
parent c6edc5c0bf
commit 74d7f49c8d
12 changed files with 125 additions and 28 deletions

View File

@@ -228,6 +228,35 @@ router.post('/notifications/toggle', express.json(), async (req, res) => {
res.json({ state: getNotificationState() });
});
// POST /gmail/reload — hot-swap Gmail OAuth creds after weekly reauth without
// restarting the process. Reads REFRESH_TOKEN from .env via configPersistence,
// probes Google with users.getProfile, and on success clears pollSuspended and
// re-installs the poll interval. On failure returns 400 with Google's error so
// the operator can see why (e.g. still invalid_grant).
router.post('/gmail/reload', express.json(), async (req, res) => {
const { reloadGmailClient } = require('../services/gmail');
const { setPollSuspended } = require('../gmail-poll');
try {
const { emailAddress } = await reloadGmailClient();
setPollSuspended(false);
// Lazy require — same reason as /restart above (module scope cycle).
const parent = require('../broccolini-discord');
if (parent.setGmailPollInterval) {
parent.setGmailPollInterval(CONFIG.GMAIL_POLL_INTERVAL_MS);
}
await logSystem('Gmail OAuth reloaded', [
{ name: 'Account', value: emailAddress, inline: false }
]).catch(() => {});
res.json({ ok: true, email: emailAddress });
} catch (err) {
const oauthError = err && err.response && err.response.data && err.response.data.error;
res.status(400).json({
ok: false,
error: oauthError || err.code || err.message || 'reload failed'
});
}
});
// Expose the allowlist for the Phase 8 schema smoke test. Attached to the
// router function object; doesn't show up as a route.
router._allowedKeys = Array.from(ALLOWED_CONFIG_KEYS);