refactor(routes): Phase 3.3 - standardize notifications.js (explicit deps)

This commit is contained in:
Krystie
2026-03-29 20:06:36 -07:00
parent f6b103aed7
commit e6e788fdce
2 changed files with 32 additions and 22 deletions

View File

@@ -3,12 +3,19 @@ const { validateURL, validateToken } = require('../input-validator');
const { paginate, parsePaginationParams } = require('../pagination'); const { paginate, parsePaginationParams } = require('../pagination');
const { ValidationError } = require('../errors'); 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(); const router = express.Router();
// GET /config — Get notification configuration (sensitive data redacted) // GET /config — Get notification configuration (sensitive data redacted)
router.get('/config', ctx.asyncHandler(async (req, res) => { router.get('/config', asyncHandler(async (req, res) => {
const notificationConfig = ctx.notification.getConfig(); const notificationConfig = notification.getConfig();
// Return config without sensitive data // Return config without sensitive data
const safeConfig = { const safeConfig = {
enabled: notificationConfig.enabled, enabled: notificationConfig.enabled,
@@ -34,9 +41,9 @@ module.exports = function(ctx) {
}, 'notifications-config-get')); }, 'notifications-config-get'));
// POST /config — Update notification configuration // 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 { enabled, providers, events, healthCheck } = req.body;
const notificationConfig = ctx.notification.getConfig(); const notificationConfig = notification.getConfig();
// Validate provider webhook URLs and tokens // Validate provider webhook URLs and tokens
if (providers) { if (providers) {
@@ -109,19 +116,19 @@ module.exports = function(ctx) {
// Restart daemon if settings changed // Restart daemon if settings changed
if (healthCheck.enabled !== wasEnabled || healthCheck.intervalMinutes) { if (healthCheck.enabled !== wasEnabled || healthCheck.intervalMinutes) {
if (notificationConfig.healthCheck.enabled) { if (notificationConfig.healthCheck.enabled) {
ctx.notification.startHealthDaemon(); notification.startHealthDaemon();
} else { } else {
ctx.notification.stopHealthDaemon(); notification.stopHealthDaemon();
} }
} }
} }
await ctx.notification.saveConfig(); await notification.saveConfig();
res.json({ success: true, message: 'Notification config updated' }); res.json({ success: true, message: 'Notification config updated' });
}, 'notifications-config-update')); }, 'notifications-config-update'));
// POST /test — Test notification delivery // POST /test — Test notification delivery
router.post('/test', ctx.asyncHandler(async (req, res) => { router.post('/test', asyncHandler(async (req, res) => {
const { provider } = req.body; const { provider } = req.body;
if (provider) { if (provider) {
@@ -129,13 +136,13 @@ module.exports = function(ctx) {
let result; let result;
switch (provider) { switch (provider) {
case 'discord': 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; break;
case 'telegram': 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; break;
case 'ntfy': 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; break;
default: default:
throw new ValidationError('Unknown provider'); throw new ValidationError('Unknown provider');
@@ -143,14 +150,14 @@ module.exports = function(ctx) {
res.json({ success: result.success, provider, error: result.error }); res.json({ success: result.success, provider, error: result.error });
} else { } else {
// Test all enabled providers // 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 }); res.json({ success: true, ...result });
} }
}, 'notifications-test')); }, 'notifications-test'));
// GET /history — Get notification history // GET /history — Get notification history
router.get('/history', ctx.asyncHandler(async (req, res) => { router.get('/history', asyncHandler(async (req, res) => {
const notificationHistory = ctx.notification.getHistory(); const notificationHistory = notification.getHistory();
const paginationParams = parsePaginationParams(req.query); const paginationParams = parsePaginationParams(req.query);
if (paginationParams) { if (paginationParams) {
const result = paginate(notificationHistory, paginationParams); const result = paginate(notificationHistory, paginationParams);
@@ -166,19 +173,19 @@ module.exports = function(ctx) {
}, 'notifications-history')); }, 'notifications-history'));
// DELETE /history — Clear notification history // DELETE /history — Clear notification history
router.delete('/history', ctx.asyncHandler(async (req, res) => { router.delete('/history', asyncHandler(async (req, res) => {
ctx.notification.clearHistory(); notification.clearHistory();
res.json({ success: true, message: 'Notification history cleared' }); res.json({ success: true, message: 'Notification history cleared' });
}, 'notifications-history-clear')); }, 'notifications-history-clear'));
// POST /health-check — Manually trigger health check // POST /health-check — Manually trigger health check
router.post('/health-check', ctx.asyncHandler(async (req, res) => { router.post('/health-check', asyncHandler(async (req, res) => {
await ctx.notification.checkHealth(); await notification.checkHealth();
const notificationConfig = ctx.notification.getConfig(); const notificationConfig = notification.getConfig();
res.json({ res.json({
success: true, success: true,
lastCheck: notificationConfig.healthCheck.lastCheck, lastCheck: notificationConfig.healthCheck.lastCheck,
containersMonitored: Object.keys(ctx.notification.getHealthState()).length containersMonitored: Object.keys(notification.getHealthState()).length
}); });
}, 'notifications-health-check')); }, 'notifications-health-check'));

View File

@@ -303,7 +303,10 @@ async function createApp() {
fetchT: ctx.fetchT, fetchT: ctx.fetchT,
credentialManager: ctx.credentialManager credentialManager: ctx.credentialManager
})); }));
apiRouter.use('/notifications', notificationRoutes(ctx)); apiRouter.use('/notifications', notificationRoutes({
notification: ctx.notification,
asyncHandler: ctx.asyncHandler
}));
apiRouter.use('/containers', containerRoutes({ apiRouter.use('/containers', containerRoutes({
docker: ctx.docker, docker: ctx.docker,
log: ctx.log, log: ctx.log,