From e6e788fdce63f2ca91d33d67385aea1340085286 Mon Sep 17 00:00:00 2001 From: Krystie Date: Sun, 29 Mar 2026 20:06:36 -0700 Subject: [PATCH] refactor(routes): Phase 3.3 - standardize notifications.js (explicit deps) --- dashcaddy-api/routes/notifications.js | 49 +++++++++++++++------------ dashcaddy-api/src/app.js | 5 ++- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/dashcaddy-api/routes/notifications.js b/dashcaddy-api/routes/notifications.js index 973ff66..27f1f8e 100644 --- a/dashcaddy-api/routes/notifications.js +++ b/dashcaddy-api/routes/notifications.js @@ -3,12 +3,19 @@ const { validateURL, validateToken } = require('../input-validator'); const { paginate, parsePaginationParams } = require('../pagination'); const { ValidationError } = require('../errors'); -module.exports = function(ctx) { +/** + * Notifications route factory + * @param {Object} deps - Explicit dependencies + * @param {Object} deps.notification - Notification manager + * @param {Function} deps.asyncHandler - Async route handler wrapper + * @returns {express.Router} + */ +module.exports = function({ notification, asyncHandler }) { const router = express.Router(); // GET /config — Get notification configuration (sensitive data redacted) - router.get('/config', ctx.asyncHandler(async (req, res) => { - const notificationConfig = ctx.notification.getConfig(); + router.get('/config', asyncHandler(async (req, res) => { + const notificationConfig = notification.getConfig(); // Return config without sensitive data const safeConfig = { enabled: notificationConfig.enabled, @@ -34,9 +41,9 @@ module.exports = function(ctx) { }, 'notifications-config-get')); // POST /config — Update notification configuration - router.post('/config', ctx.asyncHandler(async (req, res) => { + router.post('/config', asyncHandler(async (req, res) => { const { enabled, providers, events, healthCheck } = req.body; - const notificationConfig = ctx.notification.getConfig(); + const notificationConfig = notification.getConfig(); // Validate provider webhook URLs and tokens if (providers) { @@ -109,19 +116,19 @@ module.exports = function(ctx) { // Restart daemon if settings changed if (healthCheck.enabled !== wasEnabled || healthCheck.intervalMinutes) { if (notificationConfig.healthCheck.enabled) { - ctx.notification.startHealthDaemon(); + notification.startHealthDaemon(); } else { - ctx.notification.stopHealthDaemon(); + notification.stopHealthDaemon(); } } } - await ctx.notification.saveConfig(); + await notification.saveConfig(); res.json({ success: true, message: 'Notification config updated' }); }, 'notifications-config-update')); // POST /test — Test notification delivery - router.post('/test', ctx.asyncHandler(async (req, res) => { + router.post('/test', asyncHandler(async (req, res) => { const { provider } = req.body; if (provider) { @@ -129,13 +136,13 @@ module.exports = function(ctx) { let result; switch (provider) { case 'discord': - result = await ctx.notification.sendDiscord('Test Notification', 'This is a test notification from DashCaddy.', 'info'); + result = await notification.sendDiscord('Test Notification', 'This is a test notification from DashCaddy.', 'info'); break; case 'telegram': - result = await ctx.notification.sendTelegram('Test Notification', 'This is a test notification from DashCaddy.', 'info'); + result = await notification.sendTelegram('Test Notification', 'This is a test notification from DashCaddy.', 'info'); break; case 'ntfy': - result = await ctx.notification.sendNtfy('Test Notification', 'This is a test notification from DashCaddy.', 'info'); + result = await notification.sendNtfy('Test Notification', 'This is a test notification from DashCaddy.', 'info'); break; default: throw new ValidationError('Unknown provider'); @@ -143,14 +150,14 @@ module.exports = function(ctx) { res.json({ success: result.success, provider, error: result.error }); } else { // Test all enabled providers - const result = await ctx.notification.send('test', 'Test Notification', 'This is a test notification from DashCaddy.', 'info'); + const result = await notification.send('test', 'Test Notification', 'This is a test notification from DashCaddy.', 'info'); res.json({ success: true, ...result }); } }, 'notifications-test')); // GET /history — Get notification history - router.get('/history', ctx.asyncHandler(async (req, res) => { - const notificationHistory = ctx.notification.getHistory(); + router.get('/history', asyncHandler(async (req, res) => { + const notificationHistory = notification.getHistory(); const paginationParams = parsePaginationParams(req.query); if (paginationParams) { const result = paginate(notificationHistory, paginationParams); @@ -166,19 +173,19 @@ module.exports = function(ctx) { }, 'notifications-history')); // DELETE /history — Clear notification history - router.delete('/history', ctx.asyncHandler(async (req, res) => { - ctx.notification.clearHistory(); + router.delete('/history', asyncHandler(async (req, res) => { + notification.clearHistory(); res.json({ success: true, message: 'Notification history cleared' }); }, 'notifications-history-clear')); // POST /health-check — Manually trigger health check - router.post('/health-check', ctx.asyncHandler(async (req, res) => { - await ctx.notification.checkHealth(); - const notificationConfig = ctx.notification.getConfig(); + router.post('/health-check', asyncHandler(async (req, res) => { + await notification.checkHealth(); + const notificationConfig = notification.getConfig(); res.json({ success: true, lastCheck: notificationConfig.healthCheck.lastCheck, - containersMonitored: Object.keys(ctx.notification.getHealthState()).length + containersMonitored: Object.keys(notification.getHealthState()).length }); }, 'notifications-health-check')); diff --git a/dashcaddy-api/src/app.js b/dashcaddy-api/src/app.js index 172ad90..5ca9d0e 100644 --- a/dashcaddy-api/src/app.js +++ b/dashcaddy-api/src/app.js @@ -303,7 +303,10 @@ async function createApp() { fetchT: ctx.fetchT, credentialManager: ctx.credentialManager })); - apiRouter.use('/notifications', notificationRoutes(ctx)); + apiRouter.use('/notifications', notificationRoutes({ + notification: ctx.notification, + asyncHandler: ctx.asyncHandler + })); apiRouter.use('/containers', containerRoutes({ docker: ctx.docker, log: ctx.log,