@fontoxml/fontoxml-development-tools
Version:
Development tools for Fonto.
110 lines (95 loc) • 2.87 kB
JavaScript
import asyncRouteWithLockCleanupHandler from '../asyncRouteWithLockCleanupHandler.js';
/** @typedef {import('../../src/getAppConfig.js').DevCmsConfig} DevCmsConfig */
function sendJson(res, status, body) {
res
.status(status)
.set('content-type', 'application/json; charset=utf-8')
.json(body);
}
/**
* @param {DevCmsConfig} config
*/
export default function configureDocumentPutRouteHandler(config) {
return asyncRouteWithLockCleanupHandler(async (acquireLock, req, res) => {
const documentId = req.body.documentId;
if (documentId && documentId.indexOf('..') !== -1) {
res.status(403).end();
return;
}
const context = req.body.context;
const documentContext = req.body.documentContext || {};
const metadata = req.body.metadata;
const currentSession = req.getFontoSession(context.editSessionToken);
const fileLock = await acquireLock(documentId);
const contentAndLatestRevisionId = await req.cms.getFileAndLatestRevisionId(
documentId,
currentSession.editSessionToken,
fileLock,
);
if (!contentAndLatestRevisionId) {
fileLock.release();
res.status(404).end();
return;
}
const documentLoadLock = {
...config.documentLoadLock,
...config.documentLoadLockOverrides[documentId],
};
const currentState = {
lock: {
isLockAcquired:
documentContext.isLockAcquired !== undefined
? documentLoadLock.isLockAvailable && documentContext.isLockAcquired
: documentLoadLock.isLockAcquired,
isLockAvailable: documentLoadLock.isLockAvailable,
reason: !documentLoadLock.isLockAvailable
? documentLoadLock.lockReason
: undefined,
},
revisionId: contentAndLatestRevisionId.revisionId,
};
if (!currentState.lock.isLockAvailable) {
// Not available has to mean not acquired, so 412 is the correct response.
// Sending 403 here would cause the document to be considered inaccessible
// instead of merely having an unavailable lock.
fileLock.release();
sendJson(res, 412, currentState);
return;
}
if (
req.body.revisionId &&
req.body.revisionId !== currentState.revisionId
) {
fileLock.release();
sendJson(res, 412, currentState);
return;
}
if (!currentState.lock.isLockAcquired) {
fileLock.release();
sendJson(res, 412, currentState);
return;
}
const newContent = req.body.content;
let updatedRevisionId;
try {
updatedRevisionId = await req.cms.updateFile(
documentId,
newContent,
currentSession.user,
currentSession.editSessionToken,
fileLock,
);
} catch (_error) {
fileLock.release();
sendJson(res, 400, currentState);
return;
}
documentContext.isLockAcquired = currentState.lock.isLockAcquired;
documentContext.documentMetadata = metadata;
fileLock.release();
sendJson(res, 200, {
revisionId: updatedRevisionId,
documentContext,
});
});
}