UNPKG

@fontoxml/fontoxml-development-tools

Version:

Development tools for Fonto.

173 lines (158 loc) 5.12 kB
import asyncRouteWithLockCleanupHandler from '../asyncRouteWithLockCleanupHandler.js'; /** @typedef {import('../../src/getAppConfig.js').DevCmsConfig} DevCmsConfig */ let warningAboutUnsupportedConfigurationWasLogged = false; /** * @param {DevCmsConfig} config */ export default function configureDocumentStatePostRouteHandler(config) { return asyncRouteWithLockCleanupHandler(async (acquireLock, req, res) => { const results = await Promise.all( req.body.documents.map(async ({ documentContext, documentId }) => { let fileLock; let contentAndLatestRevisionId; try { fileLock = await acquireLock(documentId); contentAndLatestRevisionId = await req.cms.getFileAndLatestRevisionId( documentId, req.body.context.editSessionToken, fileLock, ); } catch (error) { fileLock?.release(); // NOTE: Status 500 is not supported per item. But be checked after all // documents have been processed, and the whole request will return 500. return { status: 500, error, }; } if (!contentAndLatestRevisionId) { fileLock?.release(); return { status: 404, }; } const documentLoadLock = { ...config.documentLoadLock, ...config.documentLoadLockOverrides[documentId], }; const revisionIdOnUnlock = config.additionalRevisionIdOn.unlock; if ( !warningAboutUnsupportedConfigurationWasLogged && revisionIdOnUnlock && documentLoadLock.releaseLocksOnStateRequest ) { console.warn( `\nGenerating additional revision id on 'unlock' while also having release locks on state request enabled. This will cause out of sync documents states.`, ); warningAboutUnsupportedConfigurationWasLogged = true; } const wasLockAcquired = documentContext ? documentLoadLock.isLockAvailable && documentContext.isLockAcquired : documentLoadLock.isLockAcquired; if ( // No need to generate a new revision id if the document will not be // released. Either due to configuration or due to it already being not // acquired. !revisionIdOnUnlock || !documentLoadLock.releaseLocksOnStateRequest || !wasLockAcquired ) { const isLockAcquired = documentLoadLock.releaseLocksOnStateRequest ? false : wasLockAcquired; const newDocumentContext = { // NOTE: documentMetadata might be undefined, that depends on the load/save. Keeping // whatever the client sends. ...documentContext, isLockAcquired, }; fileLock?.release(); return { status: 200, body: { documentContext: newDocumentContext, revisionId: contentAndLatestRevisionId.revisionId, lock: { isLockAcquired, isLockAvailable: documentLoadLock.isLockAvailable, reason: !documentLoadLock.isLockAvailable ? documentLoadLock.lockReason : undefined, }, }, }; } 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; } if (contentAndLatestRevisionId.revisionId === updatedRevisionId) { fileLock.release(); const error = new Error( `A new revision id was not generated as expected. The revision id remains: ${contentAndLatestRevisionId.revisionId}".`, ); // NOTE: Status 500 is not supported per item. But be checked after all // documents have been processed, and the whole request will return 500. return { status: 500, error, }; } const newDocumentContext = { // NOTE: documentMetadata might be undefined, that depends on the load/save. // Keeping whatever the client sends. ...documentContext, isLockAcquired: false, }; fileLock.release(); return { status: 200, body: { documentContext: newDocumentContext, revisionId: updatedRevisionId, lock: { isLockAcquired: false, isLockAvailable: documentLoadLock.isLockAvailable, reason: !documentLoadLock.isLockAvailable ? documentLoadLock.lockReason : undefined, }, }, }; }), ); // The endpoint does not support a 500 status per result, so we will return a 500 on the // whole request instead. const firstResultWithError = results.find( (result) => result.status === 500, ); if (firstResultWithError) { throw ( firstResultWithError.error ?? new Error('A result has a 500 status, which is not supported.') ); } res .status(200) .set('content-type', 'application/json; charset=utf-8') .json({ results }); }); }