BillTracker/routes/notifications.js

145 lines
5.5 KiB
JavaScript
Raw Normal View History

2026-05-03 19:51:57 -05:00
const express = require('express');
const router = express.Router();
const { getDb, getSetting, setSetting } = require('../db/database');
const { requireAuth, requireUser, requireAdmin } = require('../middleware/requireAuth');
const { sendTestEmail } = require('../services/notificationService');
const { sendTestPush } = require('../services/notificationService')._push || {};
const { decryptSecret } = require('../services/encryptionService');
2026-05-31 15:06:10 -05:00
const { encryptSecret } = require('../services/encryptionService');
2026-05-03 19:51:57 -05:00
// ── Admin: SMTP configuration ─────────────────────────────────────────────────
// GET /api/notifications/admin — read all SMTP settings (password masked)
router.get('/admin', requireAuth, requireAdmin, (req, res) => {
const keys = [
'notify_smtp_enabled', 'notify_sender_name', 'notify_sender_address',
'notify_smtp_host', 'notify_smtp_port', 'notify_smtp_encryption',
'notify_smtp_self_signed', 'notify_smtp_username', 'notify_smtp_password',
'notify_allow_user_config', 'notify_global_recipient',
];
const settings = {};
for (const k of keys) settings[k] = getSetting(k) || '';
// Mask password in response
if (settings.notify_smtp_password) settings.notify_smtp_password = '••••••••';
res.json(settings);
});
// PUT /api/notifications/admin — save SMTP settings
router.put('/admin', requireAuth, requireAdmin, (req, res) => {
const allowed = [
'notify_smtp_enabled', 'notify_sender_name', 'notify_sender_address',
'notify_smtp_host', 'notify_smtp_port', 'notify_smtp_encryption',
'notify_smtp_self_signed', 'notify_smtp_username',
'notify_allow_user_config', 'notify_global_recipient',
];
for (const key of allowed) {
if (req.body[key] !== undefined) setSetting(key, req.body[key]);
}
// Only update password if a real value was sent (not the masked placeholder)
if (req.body.notify_smtp_password && !req.body.notify_smtp_password.startsWith('•')) {
2026-05-31 15:06:10 -05:00
setSetting('notify_smtp_password', encryptSecret(req.body.notify_smtp_password));
2026-05-03 19:51:57 -05:00
}
res.json({ success: true });
});
// POST /api/notifications/test — send a test email
router.post('/test', requireAuth, requireAdmin, async (req, res) => {
const { to } = req.body;
if (!to) return res.status(400).json({ error: 'Recipient address required' });
try {
await sendTestEmail(to);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// ── User: notification preferences ───────────────────────────────────────────
// GET /api/notifications/me — user prefs + whether admin has enabled it
router.get('/me', requireAuth, requireUser, (req, res) => {
const db = getDb();
const user = db.prepare(`
SELECT notification_email, notifications_enabled,
notify_3d, notify_1d, notify_due, notify_overdue, notify_amount_change
2026-05-03 19:51:57 -05:00
FROM users WHERE id = ?
`).get(req.user.id);
res.json({
smtp_enabled: getSetting('notify_smtp_enabled') === 'true',
allow_user_config: getSetting('notify_allow_user_config') === 'true',
notification_email: user.notification_email || '',
2026-05-03 19:51:57 -05:00
notifications_enabled: !!user.notifications_enabled,
notify_3d: !!user.notify_3d,
notify_1d: !!user.notify_1d,
notify_due: !!user.notify_due,
notify_overdue: !!user.notify_overdue,
notify_amount_change: user.notify_amount_change !== 0,
2026-05-03 19:51:57 -05:00
});
});
// PUT /api/notifications/me — save user prefs
router.put('/me', requireAuth, requireUser, (req, res) => {
const db = getDb();
const {
notification_email, notifications_enabled,
notify_3d, notify_1d, notify_due, notify_overdue, notify_amount_change,
2026-05-03 19:51:57 -05:00
} = req.body;
db.prepare(`
UPDATE users SET
notification_email = ?,
notifications_enabled = ?,
notify_3d = ?,
notify_1d = ?,
notify_due = ?,
notify_overdue = ?,
notify_amount_change = ?,
2026-05-03 19:51:57 -05:00
updated_at = datetime('now')
WHERE id = ?
`).run(
notification_email || null,
notifications_enabled ? 1 : 0,
notify_3d !== false ? 1 : 0,
notify_1d !== false ? 1 : 0,
notify_due !== false ? 1 : 0,
2026-05-03 19:51:57 -05:00
notify_overdue !== false ? 1 : 0,
notify_amount_change !== false ? 1 : 0,
2026-05-03 19:51:57 -05:00
req.user.id,
);
res.json({ success: true });
});
// POST /api/notifications/test-push — send a test push notification to the current user
router.post('/test-push', requireAuth, requireUser, async (req, res) => {
const db = getDb();
const user = db.prepare(`
SELECT notify_push_enabled, push_channel, push_url, push_token, push_chat_id
FROM users WHERE id = ?
`).get(req.user.id);
if (!user?.push_channel || !user?.push_url) {
return res.status(400).json({ error: 'Push notification channel not configured' });
}
// Decrypt for sending
const safeDecrypt = (v) => { try { return v ? decryptSecret(v) : ''; } catch { return v || ''; } };
const userForPush = {
...user,
notify_push_enabled: 1,
push_url: safeDecrypt(user.push_url),
push_token: safeDecrypt(user.push_token),
};
try {
if (!sendTestPush) throw new Error('Push service not initialised');
await sendTestPush(userForPush);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
2026-05-03 19:51:57 -05:00
module.exports = router;