const express = require('express'); const { paginate, parsePaginationParams } = require('../pagination'); const { ValidationError } = require('../errors'); /** * Updates route factory * @param {Object} deps - Explicit dependencies * @param {Object} deps.updateManager - Container update manager * @param {Object} deps.selfUpdater - DashCaddy self-update manager * @param {Function} deps.asyncHandler - Async route handler wrapper * @param {Function} deps.logError - Error logging function * @returns {express.Router} */ module.exports = function({ updateManager, selfUpdater, asyncHandler, logError }) { const router = express.Router(); // ===== UPDATE MANAGEMENT ENDPOINTS ===== // Check for updates router.post('/updates/check', asyncHandler(async (req, res) => { await updateManager.checkForUpdates(); const updates = updateManager.getAvailableUpdates(); res.json({ success: true, updates, count: updates.length }); }, 'updates-check')); // Get available updates router.get('/updates/available', asyncHandler(async (req, res) => { const updates = updateManager.getAvailableUpdates(); const paginationParams = parsePaginationParams(req.query); const result = paginate(updates, paginationParams); res.json({ success: true, updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) }); }, 'updates-available')); // Update a container router.post('/updates/update/:containerId', asyncHandler(async (req, res) => { const result = await updateManager.updateContainer(req.params.containerId, req.body); res.json({ success: true, result }); }, 'updates-update')); // Rollback update router.post('/updates/rollback/:containerId', asyncHandler(async (req, res) => { await updateManager.rollbackUpdate(req.params.containerId); res.json({ success: true, message: 'Rollback completed' }); }, 'updates-rollback')); // Get update history router.get('/updates/history', asyncHandler(async (req, res) => { const paginationParams = parsePaginationParams(req.query); // When paginating, fetch all history so pagination can slice correctly const fetchLimit = paginationParams ? Number.MAX_SAFE_INTEGER : (parseInt(req.query.limit) || 50); const history = updateManager.getHistory(fetchLimit); const result = paginate(history, paginationParams); res.json({ success: true, history: result.data, ...(result.pagination && { pagination: result.pagination }) }); }, 'updates-history')); // Configure auto-update router.post('/updates/auto-update/:containerId', asyncHandler(async (req, res) => { updateManager.configureAutoUpdate(req.params.containerId, req.body); res.json({ success: true, message: 'Auto-update configured' }); }, 'updates-auto-update')); // Get auto-update configuration router.get('/updates/auto-update', asyncHandler(async (req, res) => { const config = updateManager.getAutoUpdateConfig(); res.json({ success: true, config }); }, 'updates-auto-update-config')); // Schedule update router.post('/updates/schedule/:containerId', asyncHandler(async (req, res) => { const { scheduledTime } = req.body; if (!scheduledTime) { throw new ValidationError('scheduledTime is required'); } updateManager.scheduleUpdate(req.params.containerId, scheduledTime); res.json({ success: true, message: 'Update scheduled', scheduledTime }); }, 'updates-schedule')); // ===== DASHCADDY SELF-UPDATE ENDPOINTS ===== // Get current version router.get('/system/version', asyncHandler(async (req, res) => { const local = selfUpdater.getLocalVersion(); res.json({ success: true, name: 'DashCaddy', version: local.version, commit: local.commit }); }, 'system-version')); // Check for DashCaddy update router.get('/system/update-check', asyncHandler(async (req, res) => { const result = await selfUpdater.checkForUpdate(); res.json({ success: true, ...result }); }, 'system-update-check')); // Apply available update router.post('/system/update-apply', asyncHandler(async (req, res) => { const check = await selfUpdater.checkForUpdate(); if (!check.available) { return res.json({ success: true, message: 'Already up to date' }); } // Start async — container may restart selfUpdater.applyUpdate(check.remote).catch(err => { logError('self-update', err); }); res.json({ success: true, message: 'Update initiated', fromVersion: check.local.version, toVersion: check.remote.version, }); }, 'system-update-apply')); // Get update status router.get('/system/update-status', asyncHandler(async (req, res) => { res.json({ success: true, status: selfUpdater.getStatus(), lastCheck: selfUpdater.lastCheckTime, lastResult: selfUpdater.lastCheckResult, }); }, 'system-update-status')); // Get self-update history router.get('/system/update-history', asyncHandler(async (req, res) => { const history = selfUpdater.getUpdateHistory(); res.json({ success: true, history }); }, 'system-update-history')); // List rollback versions router.get('/system/rollback-versions', asyncHandler(async (req, res) => { const versions = selfUpdater.getAvailableRollbacks(); res.json({ success: true, versions }); }, 'system-rollback-versions')); // Rollback to a previous version router.post('/system/rollback', asyncHandler(async (req, res) => { const { version } = req.body; if (!version) throw new ValidationError('version is required'); selfUpdater.rollbackToVersion(version).catch(err => { logError('self-rollback', err); }); res.json({ success: true, message: `Rollback to ${version} initiated` }); }, 'system-rollback')); return router; };