refactor(routes): Phase 3.1 - standardize updates.js (explicit deps)
This commit is contained in:
@@ -2,87 +2,96 @@ const express = require('express');
|
|||||||
const { paginate, parsePaginationParams } = require('../pagination');
|
const { paginate, parsePaginationParams } = require('../pagination');
|
||||||
const { ValidationError } = require('../errors');
|
const { ValidationError } = require('../errors');
|
||||||
|
|
||||||
module.exports = function(ctx) {
|
/**
|
||||||
|
* 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();
|
const router = express.Router();
|
||||||
|
|
||||||
// ===== UPDATE MANAGEMENT ENDPOINTS =====
|
// ===== UPDATE MANAGEMENT ENDPOINTS =====
|
||||||
|
|
||||||
// Check for updates
|
// Check for updates
|
||||||
router.post('/updates/check', ctx.asyncHandler(async (req, res) => {
|
router.post('/updates/check', asyncHandler(async (req, res) => {
|
||||||
await ctx.updateManager.checkForUpdates();
|
await updateManager.checkForUpdates();
|
||||||
const updates = ctx.updateManager.getAvailableUpdates();
|
const updates = updateManager.getAvailableUpdates();
|
||||||
res.json({ success: true, updates, count: updates.length });
|
res.json({ success: true, updates, count: updates.length });
|
||||||
}, 'updates-check'));
|
}, 'updates-check'));
|
||||||
|
|
||||||
// Get available updates
|
// Get available updates
|
||||||
router.get('/updates/available', ctx.asyncHandler(async (req, res) => {
|
router.get('/updates/available', asyncHandler(async (req, res) => {
|
||||||
const updates = ctx.updateManager.getAvailableUpdates();
|
const updates = updateManager.getAvailableUpdates();
|
||||||
const paginationParams = parsePaginationParams(req.query);
|
const paginationParams = parsePaginationParams(req.query);
|
||||||
const result = paginate(updates, paginationParams);
|
const result = paginate(updates, paginationParams);
|
||||||
res.json({ success: true, updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) });
|
res.json({ success: true, updates: result.data, count: updates.length, ...(result.pagination && { pagination: result.pagination }) });
|
||||||
}, 'updates-available'));
|
}, 'updates-available'));
|
||||||
|
|
||||||
// Update a container
|
// Update a container
|
||||||
router.post('/updates/update/:containerId', ctx.asyncHandler(async (req, res) => {
|
router.post('/updates/update/:containerId', asyncHandler(async (req, res) => {
|
||||||
const result = await ctx.updateManager.updateContainer(req.params.containerId, req.body);
|
const result = await updateManager.updateContainer(req.params.containerId, req.body);
|
||||||
res.json({ success: true, result });
|
res.json({ success: true, result });
|
||||||
}, 'updates-update'));
|
}, 'updates-update'));
|
||||||
|
|
||||||
// Rollback update
|
// Rollback update
|
||||||
router.post('/updates/rollback/:containerId', ctx.asyncHandler(async (req, res) => {
|
router.post('/updates/rollback/:containerId', asyncHandler(async (req, res) => {
|
||||||
await ctx.updateManager.rollbackUpdate(req.params.containerId);
|
await updateManager.rollbackUpdate(req.params.containerId);
|
||||||
res.json({ success: true, message: 'Rollback completed' });
|
res.json({ success: true, message: 'Rollback completed' });
|
||||||
}, 'updates-rollback'));
|
}, 'updates-rollback'));
|
||||||
|
|
||||||
// Get update history
|
// Get update history
|
||||||
router.get('/updates/history', ctx.asyncHandler(async (req, res) => {
|
router.get('/updates/history', asyncHandler(async (req, res) => {
|
||||||
const paginationParams = parsePaginationParams(req.query);
|
const paginationParams = parsePaginationParams(req.query);
|
||||||
// When paginating, fetch all history so pagination can slice correctly
|
// When paginating, fetch all history so pagination can slice correctly
|
||||||
const fetchLimit = paginationParams ? Number.MAX_SAFE_INTEGER : (parseInt(req.query.limit) || 50);
|
const fetchLimit = paginationParams ? Number.MAX_SAFE_INTEGER : (parseInt(req.query.limit) || 50);
|
||||||
const history = ctx.updateManager.getHistory(fetchLimit);
|
const history = updateManager.getHistory(fetchLimit);
|
||||||
const result = paginate(history, paginationParams);
|
const result = paginate(history, paginationParams);
|
||||||
res.json({ success: true, history: result.data, ...(result.pagination && { pagination: result.pagination }) });
|
res.json({ success: true, history: result.data, ...(result.pagination && { pagination: result.pagination }) });
|
||||||
}, 'updates-history'));
|
}, 'updates-history'));
|
||||||
|
|
||||||
// Configure auto-update
|
// Configure auto-update
|
||||||
router.post('/updates/auto-update/:containerId', ctx.asyncHandler(async (req, res) => {
|
router.post('/updates/auto-update/:containerId', asyncHandler(async (req, res) => {
|
||||||
ctx.updateManager.configureAutoUpdate(req.params.containerId, req.body);
|
updateManager.configureAutoUpdate(req.params.containerId, req.body);
|
||||||
res.json({ success: true, message: 'Auto-update configured' });
|
res.json({ success: true, message: 'Auto-update configured' });
|
||||||
}, 'updates-auto-update'));
|
}, 'updates-auto-update'));
|
||||||
|
|
||||||
// Schedule update
|
// Schedule update
|
||||||
router.post('/updates/schedule/:containerId', ctx.asyncHandler(async (req, res) => {
|
router.post('/updates/schedule/:containerId', asyncHandler(async (req, res) => {
|
||||||
const { scheduledTime } = req.body;
|
const { scheduledTime } = req.body;
|
||||||
if (!scheduledTime) {
|
if (!scheduledTime) {
|
||||||
throw new ValidationError('scheduledTime is required');
|
throw new ValidationError('scheduledTime is required');
|
||||||
}
|
}
|
||||||
ctx.updateManager.scheduleUpdate(req.params.containerId, scheduledTime);
|
updateManager.scheduleUpdate(req.params.containerId, scheduledTime);
|
||||||
res.json({ success: true, message: 'Update scheduled', scheduledTime });
|
res.json({ success: true, message: 'Update scheduled', scheduledTime });
|
||||||
}, 'updates-schedule'));
|
}, 'updates-schedule'));
|
||||||
|
|
||||||
// ===== DASHCADDY SELF-UPDATE ENDPOINTS =====
|
// ===== DASHCADDY SELF-UPDATE ENDPOINTS =====
|
||||||
|
|
||||||
// Get current version
|
// Get current version
|
||||||
router.get('/system/version', ctx.asyncHandler(async (req, res) => {
|
router.get('/system/version', asyncHandler(async (req, res) => {
|
||||||
const local = ctx.selfUpdater.getLocalVersion();
|
const local = selfUpdater.getLocalVersion();
|
||||||
res.json({ success: true, name: 'DashCaddy', version: local.version, commit: local.commit });
|
res.json({ success: true, name: 'DashCaddy', version: local.version, commit: local.commit });
|
||||||
}, 'system-version'));
|
}, 'system-version'));
|
||||||
|
|
||||||
// Check for DashCaddy update
|
// Check for DashCaddy update
|
||||||
router.get('/system/update-check', ctx.asyncHandler(async (req, res) => {
|
router.get('/system/update-check', asyncHandler(async (req, res) => {
|
||||||
const result = await ctx.selfUpdater.checkForUpdate();
|
const result = await selfUpdater.checkForUpdate();
|
||||||
res.json({ success: true, ...result });
|
res.json({ success: true, ...result });
|
||||||
}, 'system-update-check'));
|
}, 'system-update-check'));
|
||||||
|
|
||||||
// Apply available update
|
// Apply available update
|
||||||
router.post('/system/update-apply', ctx.asyncHandler(async (req, res) => {
|
router.post('/system/update-apply', asyncHandler(async (req, res) => {
|
||||||
const check = await ctx.selfUpdater.checkForUpdate();
|
const check = await selfUpdater.checkForUpdate();
|
||||||
if (!check.available) {
|
if (!check.available) {
|
||||||
return res.json({ success: true, message: 'Already up to date' });
|
return res.json({ success: true, message: 'Already up to date' });
|
||||||
}
|
}
|
||||||
// Start async — container may restart
|
// Start async — container may restart
|
||||||
ctx.selfUpdater.applyUpdate(check.remote).catch(err => {
|
selfUpdater.applyUpdate(check.remote).catch(err => {
|
||||||
ctx.logError('self-update', err);
|
logError('self-update', err);
|
||||||
});
|
});
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -93,33 +102,33 @@ module.exports = function(ctx) {
|
|||||||
}, 'system-update-apply'));
|
}, 'system-update-apply'));
|
||||||
|
|
||||||
// Get update status
|
// Get update status
|
||||||
router.get('/system/update-status', ctx.asyncHandler(async (req, res) => {
|
router.get('/system/update-status', asyncHandler(async (req, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
status: ctx.selfUpdater.getStatus(),
|
status: selfUpdater.getStatus(),
|
||||||
lastCheck: ctx.selfUpdater.lastCheckTime,
|
lastCheck: selfUpdater.lastCheckTime,
|
||||||
lastResult: ctx.selfUpdater.lastCheckResult,
|
lastResult: selfUpdater.lastCheckResult,
|
||||||
});
|
});
|
||||||
}, 'system-update-status'));
|
}, 'system-update-status'));
|
||||||
|
|
||||||
// Get self-update history
|
// Get self-update history
|
||||||
router.get('/system/update-history', ctx.asyncHandler(async (req, res) => {
|
router.get('/system/update-history', asyncHandler(async (req, res) => {
|
||||||
const history = ctx.selfUpdater.getUpdateHistory();
|
const history = selfUpdater.getUpdateHistory();
|
||||||
res.json({ success: true, history });
|
res.json({ success: true, history });
|
||||||
}, 'system-update-history'));
|
}, 'system-update-history'));
|
||||||
|
|
||||||
// List rollback versions
|
// List rollback versions
|
||||||
router.get('/system/rollback-versions', ctx.asyncHandler(async (req, res) => {
|
router.get('/system/rollback-versions', asyncHandler(async (req, res) => {
|
||||||
const versions = ctx.selfUpdater.getAvailableRollbacks();
|
const versions = selfUpdater.getAvailableRollbacks();
|
||||||
res.json({ success: true, versions });
|
res.json({ success: true, versions });
|
||||||
}, 'system-rollback-versions'));
|
}, 'system-rollback-versions'));
|
||||||
|
|
||||||
// Rollback to a previous version
|
// Rollback to a previous version
|
||||||
router.post('/system/rollback', ctx.asyncHandler(async (req, res) => {
|
router.post('/system/rollback', asyncHandler(async (req, res) => {
|
||||||
const { version } = req.body;
|
const { version } = req.body;
|
||||||
if (!version) throw new ValidationError('version is required');
|
if (!version) throw new ValidationError('version is required');
|
||||||
ctx.selfUpdater.rollbackToVersion(version).catch(err => {
|
selfUpdater.rollbackToVersion(version).catch(err => {
|
||||||
ctx.logError('self-rollback', err);
|
logError('self-rollback', err);
|
||||||
});
|
});
|
||||||
res.json({ success: true, message: `Rollback to ${version} initiated` });
|
res.json({ success: true, message: `Rollback to ${version} initiated` });
|
||||||
}, 'system-rollback'));
|
}, 'system-rollback'));
|
||||||
|
|||||||
@@ -339,7 +339,12 @@ async function createApp() {
|
|||||||
docker: ctx.docker,
|
docker: ctx.docker,
|
||||||
asyncHandler: ctx.asyncHandler
|
asyncHandler: ctx.asyncHandler
|
||||||
}));
|
}));
|
||||||
apiRouter.use(updatesRoutes(ctx));
|
apiRouter.use(updatesRoutes({
|
||||||
|
updateManager: ctx.updateManager,
|
||||||
|
selfUpdater: ctx.selfUpdater,
|
||||||
|
asyncHandler: ctx.asyncHandler,
|
||||||
|
logError: ctx.logError
|
||||||
|
}));
|
||||||
apiRouter.use('/tailscale', tailscaleRoutes(ctx));
|
apiRouter.use('/tailscale', tailscaleRoutes(ctx));
|
||||||
apiRouter.use(sitesRoutes(ctx));
|
apiRouter.use(sitesRoutes(ctx));
|
||||||
apiRouter.use(credentialsRoutes({
|
apiRouter.use(credentialsRoutes({
|
||||||
|
|||||||
Reference in New Issue
Block a user