refactor(cms): split oversized modules below the 400-line limit
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
- content-editor.js: extract the /save handler to scripts/cms-save.js - cms-logo-page.js: inline the ~280-line canvas editor script to scripts/cms-logo-client.js (page is now the HTML/CSS shell only) - cms-editor-client.js: move the keyboard-shortcut section to scripts/cms-editor-shortcuts.js, inlined after the main client All modules now under the hard limit; full pre-deploy suite green. Closes MITHOME-80
This commit is contained in:
+9
-58
@@ -17,6 +17,7 @@ const { validateContent } = require('./proto/src/content/schema');
|
||||
const { renderMarkdown } = require('./scripts/markdown-render');
|
||||
const { buildPublishCommand, interpretPublishResult } = require('./scripts/cms-publish');
|
||||
const { handleVersionRoutes, listVersions } = require('./scripts/cms-versions');
|
||||
const { handleSaveRoute } = require('./scripts/cms-save');
|
||||
const { LOGO_TARGETS, handleLogoRoutes } = require('./scripts/cms-logo');
|
||||
|
||||
const PORT = Number(process.env.CONTENT_EDITOR_PORT) || 4001;
|
||||
@@ -57,7 +58,8 @@ const { LOGO_PAGE } = require('./scripts/cms-logo-page');
|
||||
const { validateLogin, createSessionCookie, clearSessionCookie, hasValidSession, deleteSession } = require('./scripts/cms-session');
|
||||
|
||||
// Browser script is kept in its own file and inlined into the HTML template at render time.
|
||||
const clientJs = fs.readFileSync(path.join(__dirname, 'scripts', 'cms-editor-client.js'), 'utf8');
|
||||
const clientJs = fs.readFileSync(path.join(__dirname, 'scripts', 'cms-editor-client.js'), 'utf8')
|
||||
+ '\n' + fs.readFileSync(path.join(__dirname, 'scripts', 'cms-editor-shortcuts.js'), 'utf8');
|
||||
|
||||
|
||||
// ── Server ───────────────────────────────────────────────────────────────────
|
||||
@@ -230,63 +232,12 @@ const server = http.createServer(async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// POST /save — JSON body
|
||||
if (req.method === 'POST' && u.pathname === '/save') {
|
||||
let body = '';
|
||||
let bodyTooLarge = false;
|
||||
let bodySize = 0;
|
||||
req.on('data', c => {
|
||||
bodySize += c.length;
|
||||
if (bodySize > MAX_REQUEST_BODY_BYTES) {
|
||||
bodyTooLarge = true;
|
||||
return;
|
||||
}
|
||||
body += c;
|
||||
});
|
||||
req.on('end', () => {
|
||||
try {
|
||||
if (bodyTooLarge) {
|
||||
writeAudit('content_saved', { clientAddress, user: CMS_USER, file: activeFile, result: 'request_too_large' });
|
||||
res.writeHead(413, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: `A kérés túl nagy (maximum ${MAX_REQUEST_BODY_BYTES} byte)` }));
|
||||
return;
|
||||
}
|
||||
const data = JSON.parse(body);
|
||||
// Optimistic locking: the editor echoes the fingerprint of the content it
|
||||
// loaded. If the file changed since (deploy, another tab, git), a blind
|
||||
// save would silently overwrite those changes — reject with 409 instead.
|
||||
const clientHash = req.headers['x-content-hash'];
|
||||
const currentOnDisk = fs.readFileSync(FILES[activeFile], 'utf8').trim();
|
||||
const currentHash = crypto.createHash('sha256').update(currentOnDisk).digest('hex');
|
||||
if (typeof clientHash !== 'string' || clientHash !== currentHash) {
|
||||
writeAudit('content_saved', { clientAddress, user: CMS_USER, file: activeFile, result: 'conflict' });
|
||||
res.writeHead(409, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: 'A tartalom megváltozott, mióta ezt a lapot megnyitottad (pl. deploy vagy másik fül mentett). Frissítsd az oldalt, és végezd el újra a módosításokat.' }));
|
||||
return;
|
||||
}
|
||||
const validation = validateContent(activeFile, data);
|
||||
if (!validation.ok) {
|
||||
writeAudit('content_saved', { clientAddress, user: CMS_USER, file: activeFile, result: 'validation_failed' });
|
||||
res.writeHead(422, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: validation.errors.join('; '), errors: validation.errors }));
|
||||
return;
|
||||
}
|
||||
const backupFile = backupAndWriteAtomically(FILES[activeFile], data, BACKUP_DIR);
|
||||
// Return the hash of the written content so the editor tab can refresh
|
||||
// its fingerprint — otherwise the user's OWN next save would trip the
|
||||
// optimistic-lock 409 (MITHOME-68).
|
||||
const newHash = crypto.createHash('sha256').update(JSON.stringify(data, null, 2).trim()).digest('hex');
|
||||
writeAudit('content_saved', { clientAddress, user: CMS_USER, file: activeFile, result: 'ok' });
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: true, backup: path.relative(__dirname, backupFile), contentHash: newHash }));
|
||||
} catch (e) {
|
||||
writeAudit('content_saved', { clientAddress, user: CMS_USER, file: activeFile, result: 'error' });
|
||||
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: e.message }));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// POST /save — handled in scripts/cms-save.js (optimistic lock + validation + backup).
|
||||
if (handleSaveRoute({
|
||||
req, res, u, activeFile, files: FILES, maxBodyBytes: MAX_REQUEST_BODY_BYTES,
|
||||
validate: validateContent, writeAudit, backupAndWrite: backupAndWriteAtomically,
|
||||
backupDir: BACKUP_DIR, user: CMS_USER, clientAddress, cmsDirname: __dirname,
|
||||
})) return;
|
||||
|
||||
// POST /publish — Git Commit, Pull Rebase & Push
|
||||
if (req.method === 'POST' && u.pathname === '/publish') {
|
||||
|
||||
Reference in New Issue
Block a user