ImportEtherpad: Use a real ueberdb object for the temp Pad

Now plugin authors have access to the full set of DB operations.
This commit is contained in:
Richard Hansen 2022-04-19 16:23:56 -04:00
parent 6a183db850
commit 10117bc988
1 changed files with 48 additions and 54 deletions

View File

@ -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))),
]);
};