mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-08 02:52:39 -05:00
Wired up creation of post_revisions entries when saving posts with lexical (#15422)
no issue - added `PostRevsion` model - duplicated `mobiledoc_revision` creation routine in Post model's onSaving hook to create `post_revision` when model's `lexical` field has changed - updated `mobiledoc_revision` creation to skip when `lexical` field is populated
This commit is contained in:
parent
48aaa53770
commit
3b21d26be7
6 changed files with 550 additions and 85 deletions
35
ghost/core/core/server/models/post-revision.js
Normal file
35
ghost/core/core/server/models/post-revision.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
const ghostBookshelf = require('./base');
|
||||
|
||||
const PostRevision = ghostBookshelf.Model.extend({
|
||||
tableName: 'post_revisions'
|
||||
}, {
|
||||
permittedOptions(methodName) {
|
||||
let options = ghostBookshelf.Model.permittedOptions.call(this, methodName);
|
||||
const validOptions = {
|
||||
findAll: ['filter', 'columns']
|
||||
};
|
||||
|
||||
if (validOptions[methodName]) {
|
||||
options = options.concat(validOptions[methodName]);
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
orderDefaultRaw() {
|
||||
return 'created_at_ts DESC';
|
||||
},
|
||||
|
||||
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;
|
||||
return attrs;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
PostRevision: ghostBookshelf.model('PostRevision', PostRevision)
|
||||
};
|
|
@ -30,6 +30,7 @@ const messages = {
|
|||
};
|
||||
|
||||
const MOBILEDOC_REVISIONS_COUNT = 10;
|
||||
const POST_REVISIONS_COUNT = 10;
|
||||
const ALL_STATUSES = ['published', 'draft', 'scheduled', 'sent'];
|
||||
|
||||
let Post;
|
||||
|
@ -91,7 +92,7 @@ Post = ghostBookshelf.Model.extend({
|
|||
};
|
||||
},
|
||||
|
||||
relationships: ['tags', 'authors', 'mobiledoc_revisions', 'posts_meta', 'tiers'],
|
||||
relationships: ['tags', 'authors', 'mobiledoc_revisions', 'post_revisions', 'posts_meta', 'tiers'],
|
||||
|
||||
// NOTE: look up object, not super nice, but was easy to implement
|
||||
relationshipBelongsTo: {
|
||||
|
@ -776,7 +777,7 @@ Post = ghostBookshelf.Model.extend({
|
|||
}
|
||||
|
||||
// CASE: Handle mobiledoc backups/revisions. This is a pure database feature.
|
||||
if (model.hasChanged('mobiledoc') && !options.importing && !options.migrating) {
|
||||
if (model.hasChanged('mobiledoc') && !model.get('lexical') && !options.importing && !options.migrating) {
|
||||
ops.push(function updateRevisions() {
|
||||
return ghostBookshelf.model('MobiledocRevision')
|
||||
.findAll(Object.assign({
|
||||
|
@ -820,6 +821,39 @@ Post = ghostBookshelf.Model.extend({
|
|||
});
|
||||
}
|
||||
|
||||
// CASE: Handle post backups/revisions. This is a pure database feature.
|
||||
if (model.hasChanged('lexical') && !model.get('mobiledoc') && !options.importing && !options.migrating) {
|
||||
ops.push(function updateRevisions() {
|
||||
return ghostBookshelf.model('PostRevision')
|
||||
.findAll(Object.assign({
|
||||
filter: `post_id:${model.id}`,
|
||||
columns: ['id']
|
||||
}, _.pick(options, 'transacting')))
|
||||
.then((revisions) => {
|
||||
// Store previous + latest lexical content
|
||||
if (!revisions.length && options.method !== 'insert') {
|
||||
model.set('post_revisions', [{
|
||||
post_id: model.id,
|
||||
lexical: model.previous('lexical'),
|
||||
created_at_ts: Date.now() - 1
|
||||
}, {
|
||||
post_id: model.id,
|
||||
lexical: model.get('lexical'),
|
||||
created_at_ts: Date.now()
|
||||
}]);
|
||||
} else {
|
||||
const revisionsJSON = revisions.toJSON().slice(0, POST_REVISIONS_COUNT - 1);
|
||||
|
||||
model.set('post_revisions', revisionsJSON.concat([{
|
||||
post_id: model.id,
|
||||
lexical: model.get('lexical'),
|
||||
created_at_ts: Date.now()
|
||||
}]));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get('tiers')) {
|
||||
this.set('tiers', this.get('tiers').map(t => ({
|
||||
id: t.id
|
||||
|
@ -857,6 +891,10 @@ Post = ghostBookshelf.Model.extend({
|
|||
return this.hasMany('MobiledocRevision', 'post_id');
|
||||
},
|
||||
|
||||
post_revisions() {
|
||||
return this.hasMany('PostRevision', 'post_id');
|
||||
},
|
||||
|
||||
posts_meta: function postsMeta() {
|
||||
return this.hasOne('PostsMeta', 'post_id');
|
||||
},
|
||||
|
@ -927,6 +965,7 @@ Post = ghostBookshelf.Model.extend({
|
|||
|
||||
// CASE: never expose the revisions
|
||||
delete attrs.mobiledoc_revisions;
|
||||
delete attrs.post_revisions;
|
||||
|
||||
// If the current column settings allow it...
|
||||
if (!options.columns || (options.columns && options.columns.indexOf('primary_tag') > -1)) {
|
||||
|
|
|
@ -516,3 +516,283 @@ Object {
|
|||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"conversions": 0,
|
||||
"signups": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"email": null,
|
||||
"email_only": false,
|
||||
"email_segment": "all",
|
||||
"email_subject": null,
|
||||
"excerpt": "Original text",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>Original text</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"Original text\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}}",
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": null,
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"reading_time": 0,
|
||||
"slug": "lexical-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Any<Array>,
|
||||
"title": "Lexical update test",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
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": "3694",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with lexical 3: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"conversions": 0,
|
||||
"signups": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"email": null,
|
||||
"email_only": false,
|
||||
"email_segment": "all",
|
||||
"email_subject": null,
|
||||
"excerpt": "Updated text",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>Updated text</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"Updated text\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}}",
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": null,
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"reading_time": 0,
|
||||
"slug": "lexical-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Any<Array>,
|
||||
"title": "Lexical update test",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
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": "3691",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": Any<String>,
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with mobiledoc 1: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"conversions": 0,
|
||||
"signups": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"email": null,
|
||||
"email_only": false,
|
||||
"email_segment": "all",
|
||||
"email_subject": null,
|
||||
"excerpt": "Original text",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>Original text</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": null,
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": "{\\"version\\":\\"0.3.1\\",\\"ghostVersion\\":\\"4.0\\",\\"markups\\":[],\\"atoms\\":[],\\"cards\\":[],\\"sections\\":[[1,\\"p\\",[[0,[],0,\\"Original text\\"]]]]}",
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"reading_time": 0,
|
||||
"slug": "mobiledoc-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Any<Array>,
|
||||
"title": "Mobiledoc update test",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with mobiledoc 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": "3504",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with mobiledoc 3: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"conversions": 0,
|
||||
"signups": 0,
|
||||
},
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"custom_excerpt": null,
|
||||
"custom_template": null,
|
||||
"email": null,
|
||||
"email_only": false,
|
||||
"email_segment": "all",
|
||||
"email_subject": null,
|
||||
"excerpt": "Updated text",
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"html": "<p>Updated text</p>",
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": null,
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": "{\\"version\\":\\"0.3.1\\",\\"ghostVersion\\":\\"4.0\\",\\"markups\\":[],\\"atoms\\":[],\\"cards\\":[],\\"sections\\":[[1,\\"p\\",[[0,[],0,\\"Updated text\\"]]]]}",
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"reading_time": 0,
|
||||
"slug": "mobiledoc-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Any<Array>,
|
||||
"title": "Mobiledoc update test",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": Any<String>,
|
||||
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
|
||||
"visibility": "public",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with mobiledoc 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": "3501",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": Any<String>,
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const should = require('should');
|
||||
const assert = require('assert');
|
||||
const {agentProvider, fixtureManager, mockManager, matchers} = require('../../utils/e2e-framework');
|
||||
const {anyArray, anyEtag, anyErrorId, anyLocationFor, anyObject, anyObjectId, anyISODateTime, anyString, anyUuid} = matchers;
|
||||
const models = require('../../../core/server/models');
|
||||
|
||||
const matchPostShallowIncludes = {
|
||||
id: anyObjectId,
|
||||
|
@ -17,6 +19,53 @@ const matchPostShallowIncludes = {
|
|||
published_at: anyISODateTime
|
||||
};
|
||||
|
||||
const createLexical = (text) => {
|
||||
return JSON.stringify({
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text,
|
||||
type: 'text',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const createMobiledoc = (text) => {
|
||||
return JSON.stringify({
|
||||
version: '0.3.1',
|
||||
ghostVersion: '4.0',
|
||||
markups: [],
|
||||
atoms: [],
|
||||
cards: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, text]
|
||||
]]
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
describe('Posts API', function () {
|
||||
let agent;
|
||||
|
||||
|
@ -56,18 +105,7 @@ describe('Posts API', function () {
|
|||
it('Can create a post with mobiledoc', async function () {
|
||||
const post = {
|
||||
title: 'Mobiledoc test',
|
||||
mobiledoc: JSON.stringify({
|
||||
version: '0.3.1',
|
||||
ghostVersion: '4.0',
|
||||
markups: [],
|
||||
atoms: [],
|
||||
cards: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Testing post creation with mobiledoc']
|
||||
]]
|
||||
]
|
||||
}),
|
||||
mobiledoc: createMobiledoc('Testing post creation with mobiledoc'),
|
||||
lexical: null
|
||||
};
|
||||
|
||||
|
@ -85,41 +123,15 @@ describe('Posts API', function () {
|
|||
});
|
||||
|
||||
it('Can create a post with lexical', async function () {
|
||||
const lexical = createLexical('Testing post creation with lexical');
|
||||
|
||||
const post = {
|
||||
title: 'Lexical test',
|
||||
mobiledoc: null,
|
||||
lexical: JSON.stringify({
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Testing post creation with lexical',
|
||||
type: 'text',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1
|
||||
}
|
||||
})
|
||||
lexical
|
||||
};
|
||||
|
||||
await agent
|
||||
const {body} = await agent
|
||||
.post('/posts/?formats=mobiledoc,lexical,html')
|
||||
.body({posts: [post]})
|
||||
.expectStatus(201)
|
||||
|
@ -130,52 +142,32 @@ describe('Posts API', function () {
|
|||
etag: anyEtag,
|
||||
location: anyLocationFor('posts')
|
||||
});
|
||||
|
||||
const [postResponse] = body.posts;
|
||||
|
||||
// post revision is created
|
||||
const postRevisions = await models.PostRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
postRevisions.length.should.equal(1);
|
||||
postRevisions.at(0).get('lexical').should.equal(lexical);
|
||||
|
||||
// mobiledoc revision is not created
|
||||
const mobiledocRevisions = await models.MobiledocRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
mobiledocRevisions.length.should.equal(0);
|
||||
});
|
||||
|
||||
it('Errors if both mobiledoc and lexical are present', async function () {
|
||||
const post = {
|
||||
title: 'Mobiledoc+lexical test',
|
||||
mobiledoc: JSON.stringify({
|
||||
version: '0.3.1',
|
||||
ghostVersion: '4.0',
|
||||
markups: [],
|
||||
atoms: [],
|
||||
cards: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Testing post creation with mobiledoc']
|
||||
]]
|
||||
]
|
||||
}),
|
||||
lexical: JSON.stringify({
|
||||
root: {
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Testing post creation with lexical',
|
||||
type: 'text',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'paragraph',
|
||||
version: 1
|
||||
}
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
type: 'root',
|
||||
version: 1
|
||||
}
|
||||
})
|
||||
mobiledoc: createMobiledoc('Testing post creation with mobiledoc'),
|
||||
lexical: createLexical('Testing post creation with lexical')
|
||||
};
|
||||
|
||||
await agent
|
||||
|
@ -215,6 +207,112 @@ describe('Posts API', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Update', function () {
|
||||
it('Can update a post with mobiledoc', async function () {
|
||||
const originalMobiledoc = createMobiledoc('Original text');
|
||||
const updatedMobiledoc = createMobiledoc('Updated text');
|
||||
|
||||
const {body: postBody} = await agent
|
||||
.post('/posts/?formats=mobiledoc,lexical,html')
|
||||
.body({posts: [{
|
||||
title: 'Mobiledoc update test',
|
||||
mobiledoc: originalMobiledoc
|
||||
}]})
|
||||
.expectStatus(201)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign(matchPostShallowIncludes, {published_at: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag,
|
||||
location: anyLocationFor('posts')
|
||||
});
|
||||
|
||||
const [postResponse] = postBody.posts;
|
||||
|
||||
await agent
|
||||
.put(`/posts/${postResponse.id}/?formats=mobiledoc,lexical,html`)
|
||||
.body({posts: [Object.assign({}, postResponse, {mobiledoc: updatedMobiledoc})]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign(matchPostShallowIncludes, {published_at: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag,
|
||||
'x-cache-invalidate': anyString
|
||||
});
|
||||
|
||||
// mobiledoc revisions are created
|
||||
const mobiledocRevisions = await models.MobiledocRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
mobiledocRevisions.length.should.equal(2);
|
||||
mobiledocRevisions.at(0).get('mobiledoc').should.equal(updatedMobiledoc);
|
||||
mobiledocRevisions.at(1).get('mobiledoc').should.equal(originalMobiledoc);
|
||||
|
||||
// post revisions are not created
|
||||
const postRevisions = await models.PostRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
postRevisions.length.should.equal(0);
|
||||
});
|
||||
|
||||
it('Can update a post with lexical', async function () {
|
||||
const originalLexical = createLexical('Original text');
|
||||
const updatedLexical = createLexical('Updated text');
|
||||
|
||||
const {body: postBody} = await agent
|
||||
.post('/posts/?formats=mobiledoc,lexical,html')
|
||||
.body({posts: [{
|
||||
title: 'Lexical update test',
|
||||
lexical: originalLexical
|
||||
}]})
|
||||
.expectStatus(201)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign(matchPostShallowIncludes, {published_at: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag,
|
||||
location: anyLocationFor('posts')
|
||||
});
|
||||
|
||||
const [postResponse] = postBody.posts;
|
||||
|
||||
await agent
|
||||
.put(`/posts/${postResponse.id}/?formats=mobiledoc,lexical,html`)
|
||||
.body({posts: [Object.assign({}, postResponse, {lexical: updatedLexical})]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign(matchPostShallowIncludes, {published_at: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag,
|
||||
'x-cache-invalidate': anyString
|
||||
});
|
||||
|
||||
// post revisions are created
|
||||
const postRevisions = await models.PostRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
postRevisions.length.should.equal(2);
|
||||
postRevisions.at(0).get('lexical').should.equal(updatedLexical);
|
||||
postRevisions.at(1).get('lexical').should.equal(originalLexical);
|
||||
|
||||
// mobiledoc revisions are not created
|
||||
const mobiledocRevisions = await models.MobiledocRevision
|
||||
.where('post_id', postResponse.id)
|
||||
.orderBy('created_at_ts', 'desc')
|
||||
.fetchAll();
|
||||
|
||||
mobiledocRevisions.length.should.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete', function () {
|
||||
it('Can destroy a post', async function () {
|
||||
await agent
|
||||
|
|
|
@ -97,6 +97,7 @@ describe('Exporter', function () {
|
|||
const excludedTables = [
|
||||
'sessions',
|
||||
'mobiledoc_revisions',
|
||||
'post_revisions',
|
||||
'email_batches',
|
||||
'email_recipients',
|
||||
'members_cancel_events',
|
||||
|
|
|
@ -250,6 +250,18 @@ describe('Unit: models/post', function () {
|
|||
should.not.exist(json.mobiledoc_revisions);
|
||||
should.exist(json.mobiledoc);
|
||||
});
|
||||
|
||||
it('ensure post revisions are never exposed', function () {
|
||||
const post = {
|
||||
lexical: '{}',
|
||||
post_revisions: []
|
||||
};
|
||||
|
||||
const json = toJSON(post, {formats: ['lexical']});
|
||||
|
||||
should.not.exist(json.post_revisions);
|
||||
should.exist(json.lexical);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extraFilters', function () {
|
||||
|
|
Loading…
Add table
Reference in a new issue