Files
dashcaddy/dashcaddy-api/routes/config/settings.js
T
Hermes 7bc2a207f3 DC-005: Fix all 138 broken test paths after src/ refactor
After the DC-005 module reorganization (41 files moved into src/ subdirs),
138 test suites failed because the refactor script's path-rewrite logic
missed three categories:

1. Files inside src/ doing 'require("./src/...")' — should be 'require("../...")'
2. Files in src/X/Y/ doing 'require("../../../src/...")' — should be 'require("../../...")'
3. Test files in __tests__/ with leftover 'require("../../../src/...")' paths

Root cause: the original refactor script ran before all files were moved,
so it computed relative paths against stale filesystem state.

Result:
- 30/30 test suites pass
- 879/879 tests pass (was: 18/30 suites, 614/687 tests)

Also fixed:
- routes/apps/restore.js: wrong responses import path
- routes/*/*.js: '../../src/utilities/X' → '../src/utilities/X' (depth 2 routes)
2026-06-13 12:16:56 -07:00

87 lines
3.2 KiB
JavaScript

const fsp = require('fs').promises;
const { validateConfig } = require('../../../src/utilities/config-schema');
const { exists } = require('../../../src/utilities/fs-helpers');
const { ValidationError } = require('../../../src/utilities/errors');
const { ok, successMessage } = require('../src/utils/responses');
/**
* Config settings routes factory
* @param {Object} deps - Explicit dependencies
* @param {Object} deps.configStateManager - Config state manager
* @param {Function} deps.asyncHandler - Async route handler wrapper
* @param {Object} deps.log - Logger instance
* @param {string} deps.CONFIG_FILE - Config file path
* @param {Function} deps.errorResponse - Error response helper
* @param {Function} deps.loadSiteConfig - Site config reload helper
* @returns {express.Router}
*/
module.exports = function({ configStateManager: _configStateManager, asyncHandler, log, CONFIG_FILE, errorResponse, loadSiteConfig }) {
const express = require('express');
const router = express.Router();
const ctx = { CONFIG_FILE, errorResponse, loadSiteConfig };
// ===== DASHCADDY CONFIG ENDPOINTS =====
// Server-side config storage for setup wizard (shared across all browsers/machines)
router.get('/config', asyncHandler(async (req, res) => {
if (!await exists(ctx.CONFIG_FILE)) {
return res.json({ setupComplete: false });
}
const data = await fsp.readFile(ctx.CONFIG_FILE, 'utf8');
const config = JSON.parse(data);
res.json(config);
}, 'config-get'));
router.post('/config', asyncHandler(async (req, res) => {
const incoming = req.body;
if (!incoming || typeof incoming !== 'object') {
throw new ValidationError('Invalid config object');
}
// Merge with existing config so partial saves don't wipe fields
let existing = {};
if (await exists(ctx.CONFIG_FILE)) {
try {
existing = JSON.parse(await fsp.readFile(ctx.CONFIG_FILE, 'utf8'));
} catch (_) { /* start fresh if file is corrupt */ }
}
const config = { ...existing, ...incoming };
// Merge nested dns object so partial dns updates don't wipe dns fields
if (existing.dns && incoming.dns) {
config.dns = { ...existing.dns, ...incoming.dns };
}
// Merge nested dnsServers object
if (existing.dnsServers && incoming.dnsServers) {
config.dnsServers = { ...existing.dnsServers, ...incoming.dnsServers };
}
// Validate merged config against schema
const { valid, errors, warnings } = validateConfig(config);
if (!valid) {
return ctx.errorResponse(res, 400, 'Config validation failed', { errors });
}
// Add timestamp
config.updatedAt = new Date().toISOString();
await fsp.writeFile(ctx.CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
if (typeof ctx.loadSiteConfig === 'function') {
ctx.loadSiteConfig(); // Refresh in-memory config
}
log.info('config', 'Config saved', { path: ctx.CONFIG_FILE });
ok(res, { message: 'Configuration saved', config, warnings });
}, 'config-save'));
router.delete('/config', asyncHandler(async (req, res) => {
if (await exists(ctx.CONFIG_FILE)) {
await fsp.unlink(ctx.CONFIG_FILE);
}
successMessage(res, 'Configuration reset');
}, 'config-delete'));
return router;
};