diff --git a/src/node/utils/ImportEtherpad.js b/src/node/utils/ImportEtherpad.js index de0280e23..6afc0bea3 100644 --- a/src/node/utils/ImportEtherpad.js +++ b/src/node/utils/ImportEtherpad.js @@ -24,6 +24,7 @@ const db = require('../db/DB'); const hooks = require('../../static/js/pluginfw/hooks'); const log4js = require('log4js'); const supportedElems = require('../../static/js/contentcollector').supportedElems; +const ueberdb = require('ueberdb2'); const logger = log4js.getLogger('ImportEtherpad'); @@ -55,66 +56,59 @@ exports.setPadRaw = async (padId, r, authorId = '') => { // First validate and transform values. Do not commit any records to the database yet in case // there is a problem with the data. - const dbRecords = new Map(); + const data = new Map(); const existingAuthors = new Set(); - await Promise.all(Object.entries(records).map(([key, value]) => q.pushAsync(async () => { - if (!value) { - return; - } - const keyParts = key.split(':'); - const [prefix, id] = keyParts; - if (prefix === 'globalAuthor' && keyParts.length === 2) { - // In the database, the padIDs subkey is an object (which is used as a set) that records every - // pad the author has worked on. When exported, that object becomes a single string containing - // the exported pad's ID. - if (typeof value.padIDs !== 'string') { - throw new TypeError('globalAuthor padIDs subkey is not a string'); - } - checkOriginalPadId(value.padIDs); - if (await authorManager.doesAuthorExist(id)) { - existingAuthors.add(id); + const padDb = new ueberdb.Database('memory', {data}); + await padDb.init(); + try { + await Promise.all(Object.entries(records).map(([key, value]) => q.pushAsync(async () => { + if (!value) return; + const keyParts = key.split(':'); + const [prefix, id] = keyParts; + if (prefix === 'globalAuthor' && keyParts.length === 2) { + // In the database, the padIDs subkey is an object (which is used as a set) that records + // every pad the author has worked on. When exported, that object becomes a single string + // containing the exported pad's ID. + if (typeof value.padIDs !== 'string') { + throw new TypeError('globalAuthor padIDs subkey is not a string'); + } + checkOriginalPadId(value.padIDs); + if (await authorManager.doesAuthorExist(id)) { + existingAuthors.add(id); + return; + } + value.padIDs = {[padId]: 1}; + } else if (padKeyPrefixes.includes(prefix)) { + checkOriginalPadId(id); + if (prefix === 'pad' && keyParts.length === 2) { + const pool = new AttributePool().fromJsonable(value.pool); + const unsupportedElements = new Set(); + pool.eachAttrib((k, v) => { + if (!supportedElems.has(k)) unsupportedElements.add(k); + }); + if (unsupportedElements.size) { + logger.warn(`(pad ${padId}) unsupported attributes (try installing a plugin): ` + + `${[...unsupportedElements].join(', ')}`); + } + } + keyParts[1] = padId; + key = keyParts.join(':'); + } else { + logger.warn(`(pad ${padId}) Ignoring record with unsupported key: ${key}`); return; } - value.padIDs = {[padId]: 1}; - } else if (padKeyPrefixes.includes(prefix)) { - checkOriginalPadId(id); - if (prefix === 'pad' && keyParts.length === 2) { - const pool = new AttributePool().fromJsonable(value.pool); - const unsupportedElements = new Set(); - pool.eachAttrib((k, v) => { - if (!supportedElems.has(k)) unsupportedElements.add(k); - }); - if (unsupportedElements.size) { - logger.warn(`(pad ${padId}) unsupported attributes (try installing a plugin): ` + - `${[...unsupportedElements].join(', ')}`); - } - } - keyParts[1] = padId; - key = keyParts.join(':'); - } else { - logger.warn(`(pad ${padId}) Ignoring record with unsupported key: ${key}`); - return; - } - dbRecords.set(key, value); - }))); + await padDb.set(key, value); + }))); - const pad = new Pad(padId, { - // Only fetchers are needed to check the pad's integrity. - get: async (k) => dbRecords.get(k), - getSub: async (k, sub) => { - let v = dbRecords.get(k); - for (const sk of sub) { - if (v == null) return null; - v = v[sk]; - } - return v; - }, - }); - await pad.init(null, authorId); - await pad.check(); + const pad = new Pad(padId, padDb); + await pad.init(null, authorId); + await pad.check(); + } finally { + await padDb.close(); + } await Promise.all([ - ...[...dbRecords].map(([k, v]) => q.pushAsync(() => db.set(k, v))), + ...[...data].map(([k, v]) => q.pushAsync(() => db.set(k, v))), ...[...existingAuthors].map((a) => q.pushAsync(() => authorManager.addPad(a, padId))), ]); };