ghost
Version:
The professional publishing platform
73 lines (58 loc) • 2.65 kB
JavaScript
const logging = require('../../../../../shared/logging');
const {createIrreversibleMigration} = require('../../utils');
const mobiledocLib = require('../../../../lib/mobiledoc');
const htmlToText = require('html-to-text');
module.exports = createIrreversibleMigration(async (knex) => {
logging.info('Starting re-generation of posts html.');
await knex.transaction(async (trx) => {
// get list of posts ids, use .forUpdate to lock rows until the transaction is finished
const postIdRows = await knex('posts')
.transacting(trx)
.forUpdate()
.select('id');
// transform each post individually to avoid dumping all posts into memory and
// pushing all queries into the query builder buffer in parallel
// https://stackoverflow.com/questions/54105280/how-to-loop-through-multi-line-sql-query-and-use-them-in-knex-transactions
for (const postIdRow of postIdRows) {
const {id} = postIdRow;
const [post] = await knex('posts')
.transacting(trx)
.where({id})
.select('mobiledoc', 'html', 'plaintext');
let mobiledoc;
try {
mobiledoc = JSON.parse(post.mobiledoc || null);
if (!mobiledoc) {
return logging.warn(`No mobiledoc for ${id}. Skipping.`);
}
} catch (err) {
return logging.warn(`Invalid JSON structure for ${id}. Skipping`);
}
const html = mobiledocLib.mobiledocHtmlRenderer.render(mobiledoc);
const updatedAttrs = {
html: html
};
// NOTE: block comes straight from the Post model
// https://github.com/TryGhost/Ghost/blob/4.0.0-alpha.2/core/server/models/post.js#L484
if (html !== post.html || !post.plaintext) {
const plaintext = htmlToText.fromString(html, {
wordwrap: 80,
ignoreImage: true,
hideLinkHrefIfSameAsText: true,
preserveNewlines: true,
returnDomByDefault: true,
uppercaseHeadings: false
});
if (plaintext !== post.plaintext) {
updatedAttrs.plaintext = plaintext;
}
}
await knex('posts')
.transacting(trx)
.where({id})
.update(updatedAttrs);
}
return 'transaction complete';
});
logging.info('Finished re-generation of posts html.');
});