UNPKG

@fontoxml/fontoxml-development-tools

Version:

Development tools for Fonto.

131 lines (116 loc) 3.62 kB
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 configureDocumentLockPutRouteHandler(config) { return asyncRouteWithLockCleanupHandler(async (acquireLock, req, res) => { const documentId = req.body.documentId; const revisionId = req.body.revisionId; const lock = req.body.lock; const documentContext = req.body.documentContext || {}; const fileLock = await acquireLock(documentId); const contentAndLatestRevisionId = await req.cms.getFileAndLatestRevisionId( documentId, req.body.context.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) { // 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 (revisionId !== contentAndLatestRevisionId.revisionId) { fileLock.release(); sendJson(res, 412, currentState); return; } // Store lock state on the client for simplicity const newDocumentContext = { // NOTE: documentMetadata might be undefined, that depends on the load/save. Keeping // whatever the client sends. ...documentContext, isLockAcquired: lock.isLockAcquired, }; const shouldGenerateAdditionalRevisionId = lock.isLockAcquired ? config.additionalRevisionIdOn.lock : config.additionalRevisionIdOn.unlock; if (!shouldGenerateAdditionalRevisionId) { fileLock.release(); sendJson(res, 200, { documentContext: newDocumentContext, lock: { ...currentState.lock, isLockAcquired: lock.isLockAcquired, }, revisionId: contentAndLatestRevisionId.revisionId, }); return; } const currentSession = req.getFontoSession( req.body.context.editSessionToken, ); let updatedRevisionId; try { updatedRevisionId = await req.cms.updateFile( documentId, contentAndLatestRevisionId.content, currentSession.user, currentSession.editSessionToken, fileLock, ); } catch (error) { if (error.statusCode === 404) { // Should not happen, as we already checked the existence of the document. fileLock.release(); res.status(404).end(); return; } throw error; } fileLock.release(); if (contentAndLatestRevisionId.revisionId === updatedRevisionId) { throw new Error( `A new revision id was not generated as expected. The revision id remains: ${contentAndLatestRevisionId.revisionId}".`, ); } sendJson(res, 200, { documentContext: newDocumentContext, lock: { ...currentState.lock, isLockAcquired: lock.isLockAcquired, }, revisionId: updatedRevisionId, }); }); }