Added background saves every 10 mins for post-revisions (#16703)

no issue
This commit is contained in:
Chris Raible 2023-04-21 16:04:54 +01:00 committed by GitHub
parent f92def8dde
commit 58efca6c04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 13 deletions

View File

@ -36,8 +36,8 @@ const PostRevision = ghostBookshelf.Model.extend({
toJSON(unfilteredOptions) {
const options = PostRevision.filterOptions(unfilteredOptions, 'toJSON');
const attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
// CASE: only for internal accuracy
delete attrs.created_at_ts;
// We embed the full author object, so no need to send the author_id
delete attrs.author_id;
return attrs;
}

View File

@ -37,6 +37,7 @@ const messages = {
const MOBILEDOC_REVISIONS_COUNT = 10;
const POST_REVISIONS_COUNT = 10;
const POST_REVISIONS_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
const ALL_STATUSES = ['published', 'draft', 'scheduled', 'sent'];
let Post;
@ -905,7 +906,8 @@ Post = ghostBookshelf.Model.extend({
if (!model.get('mobiledoc') && !options.importing && !options.migrating) {
const postRevisions = new PostRevisions({
config: {
max_revisions: POST_REVISIONS_COUNT
max_revisions: POST_REVISIONS_COUNT,
revision_interval_ms: POST_REVISIONS_INTERVAL_MS
}
});
const authorId = this.contextUser(options);
@ -913,7 +915,7 @@ Post = ghostBookshelf.Model.extend({
const revisionModels = await ghostBookshelf.model('PostRevision')
.findAll(Object.assign({
filter: `post_id:${model.id}`,
columns: ['id', 'lexical', 'created_at', 'author_id', 'title', 'reason', 'post_status']
columns: ['id', 'lexical', 'created_at', 'author_id', 'title', 'reason', 'post_status', 'created_at_ts']
}, _.pick(options, 'transacting')));
const revisions = revisionModels.toJSON();

View File

@ -831,7 +831,7 @@ exports[`Posts API Create Can create a post with lexical 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "5363",
"content-length": "5396",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -1261,7 +1261,7 @@ exports[`Posts API Update Can update a post with lexical 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "5249",
"content-length": "5333",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -1371,7 +1371,7 @@ exports[`Posts API Update Can update a post with lexical 4: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "6619",
"content-length": "6685",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,

View File

@ -31,6 +31,7 @@ class PostRevisions {
* @param {object} deps
* @param {object} deps.config
* @param {number} deps.config.max_revisions
* @param {number} deps.config.revision_interval_ms
* @param {object} deps.model
*/
constructor(deps) {
@ -57,11 +58,19 @@ class PostRevisions {
}
const forceRevision = options && options.forceRevision;
const lexicalHasChangedSinceLatestRevision = latestRevision.lexical !== current.lexical;
const titleHasChanged = latestRevision.title !== current.title;
const featuredImagedHasChanged = latestRevision.feature_image !== current.feature_image;
if ((lexicalHasChangedSinceLatestRevision || titleHasChanged || featuredImagedHasChanged) && forceRevision) {
return {value: true, reason: 'explicit_save'};
const lexicalHasChanged = latestRevision.lexical !== current.lexical;
const titleHasChanged = latestRevision.title !== current.title;
// CASE: we only want to save a revision if something has changed since the previous revision
if (lexicalHasChanged || titleHasChanged || featuredImagedHasChanged) {
// CASE: user has explicitly requested a revision by hitting cmd+s or leaving the editor
if (forceRevision) {
return {value: true, reason: 'explicit_save'};
}
// CASE: it's been X mins since the last revision, so we should save a new one
if ((Date.now() - latestRevision.created_at_ts) > this.config.revision_interval_ms) {
return {value: true, reason: 'background_save'};
}
}
return {value: false};
}

View File

@ -3,7 +3,8 @@ const sinon = require('sinon');
const PostRevisions = require('..');
const config = {
max_revisions: 10
max_revisions: 10,
revision_interval_ms: 1000
};
describe('PostRevisions', function () {
@ -58,7 +59,8 @@ describe('PostRevisions', function () {
html: 'blah',
title: 'blah2'
}, [{
lexical: 'blah'
lexical: 'blah',
title: 'not blah'
}], {
forceRevision: true
});
@ -103,6 +105,22 @@ describe('PostRevisions', function () {
assert.deepEqual(actual, expected);
});
it('should return true if the latest revision was more than the interval', function () {
const postRevisions = new PostRevisions({config});
const expected = {value: true, reason: 'background_save'};
const actual = postRevisions.shouldGenerateRevision({
lexical: 'blah',
html: 'blah',
title: 'blah'
}, [{
lexical: 'blah',
created_at_ts: Date.now() - 2000
}], {});
assert.deepEqual(actual, expected);
});
});
describe('getRevisions', function () {