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:
@@ -0,0 +1,65 @@
|
||||
// POST /save handler for the Content Editor — extracted to keep content-editor.js
|
||||
// under the 400-line hard limit. Returns true when the request was handled.
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
function handleSaveRoute({
|
||||
req, res, u, activeFile, files, maxBodyBytes, validate,
|
||||
writeAudit, backupAndWrite, backupDir, user, clientAddress, cmsDirname,
|
||||
}) {
|
||||
if (req.method !== 'POST' || u.pathname !== '/save') return false;
|
||||
|
||||
let body = '';
|
||||
let bodyTooLarge = false;
|
||||
let bodySize = 0;
|
||||
req.on('data', c => {
|
||||
bodySize += c.length;
|
||||
if (bodySize > maxBodyBytes) { bodyTooLarge = true; return; }
|
||||
body += c;
|
||||
});
|
||||
req.on('end', () => {
|
||||
try {
|
||||
if (bodyTooLarge) {
|
||||
writeAudit('content_saved', { clientAddress, 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 ${maxBodyBytes} 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, 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 = validate(activeFile, data);
|
||||
if (!validation.ok) {
|
||||
writeAudit('content_saved', { clientAddress, 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 = backupAndWrite(files[activeFile], data, backupDir);
|
||||
// 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 lock.
|
||||
const newHash = crypto.createHash('sha256').update(JSON.stringify(data, null, 2).trim()).digest('hex');
|
||||
writeAudit('content_saved', { clientAddress, user, file: activeFile, result: 'ok' });
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: true, backup: path.relative(cmsDirname, backupFile), contentHash: newHash }));
|
||||
} catch (e) {
|
||||
writeAudit('content_saved', { clientAddress, user, file: activeFile, result: 'error' });
|
||||
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: false, error: e.message }));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = { handleSaveRoute };
|
||||
Reference in New Issue
Block a user