Supported adding/removing post to collection via Posts API
We've got some fairly simple diffing logic here to update the collections which a post is in, the bulk of the changes here are to support the return of a DTO rather than Bookshelf Model. This also helps improve the architecture because we are step closer to removing infrastructure concerns (HTTP Response Headers) from the business logic layer. For now there is a crappy EventString which can be passed back to the controller which can then handle any HTTP related concerns, although long term these should be actual events like PostPublished or PostUpdated.
This commit is contained in:
parent
f3f9e5a2f3
commit
0d7f98f4d1
@ -1,3 +1,4 @@
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
const models = require('../../models');
|
||||
const getPostServiceInstance = require('../../services/posts/posts-service');
|
||||
const allowedIncludes = [
|
||||
@ -21,6 +22,22 @@ const unsafeAttrs = ['status', 'authors', 'visibility'];
|
||||
|
||||
const postsService = getPostServiceInstance();
|
||||
|
||||
/**
|
||||
* @param {string} event
|
||||
*/
|
||||
function getCacheHeaderFromEventString(event, dto) {
|
||||
if (event === 'published_updated' || event === 'unpublished') {
|
||||
return true;
|
||||
}
|
||||
if (event === 'scheduled_updated' || event === 'draft_updated') {
|
||||
return {
|
||||
value: urlUtils.urlFor({
|
||||
relativeUrl: urlUtils.urlJoin('/p', dto.uuid, '/')
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
docName: 'posts',
|
||||
browse: {
|
||||
@ -162,6 +179,7 @@ module.exports = {
|
||||
|
||||
edit: {
|
||||
headers: {
|
||||
/** @type {boolean | {value: string}} */
|
||||
cacheInvalidate: false
|
||||
},
|
||||
options: [
|
||||
@ -194,9 +212,11 @@ module.exports = {
|
||||
unsafeAttrs: unsafeAttrs
|
||||
},
|
||||
async query(frame) {
|
||||
let model = await postsService.editPost(frame);
|
||||
|
||||
this.headers.cacheInvalidate = postsService.handleCacheInvalidation(model);
|
||||
let model = await postsService.editPost(frame, {
|
||||
eventHandler: (event, dto) => {
|
||||
this.headers.cacheInvalidate = getCacheHeaderFromEventString(event, dto);
|
||||
}
|
||||
});
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -974,6 +974,363 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can add and remove collections 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 {
|
||||
"clicks": 0,
|
||||
"negative_feedback": 0,
|
||||
"positive_feedback": 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": null,
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": "{\\"version\\":\\"0.3.1\\",\\"ghostVersion\\":\\"4.0\\",\\"markups\\":[],\\"atoms\\":[],\\"cards\\":[],\\"sections\\":[[1,\\"p\\",[[0,[],0,\\"\\"]]]]}",
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"post_revisions": Any<Array>,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"slug": "collection-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Array [
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": null,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": null,
|
||||
"monthly_price_id": null,
|
||||
"name": "Free",
|
||||
"slug": "free",
|
||||
"trial_days": 0,
|
||||
"type": "free",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": null,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": 500,
|
||||
"monthly_price_id": null,
|
||||
"name": "Default Product",
|
||||
"slug": "default-product",
|
||||
"trial_days": 0,
|
||||
"type": "paid",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": 5000,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
],
|
||||
"title": "Collection 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 add and remove collections 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": "3701",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can add and remove collections 3: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"collections": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.\\\\d\\{3\\}Z/,
|
||||
"description": null,
|
||||
"feature_image": null,
|
||||
"filter": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"posts": Array [
|
||||
Object {
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"sort_order": 0,
|
||||
},
|
||||
],
|
||||
"title": "Collection to remove.",
|
||||
"type": "manual",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.\\\\d\\{3\\}Z/,
|
||||
},
|
||||
],
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"clicks": 0,
|
||||
"negative_feedback": 0,
|
||||
"positive_feedback": 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": null,
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": "{\\"version\\":\\"0.3.1\\",\\"ghostVersion\\":\\"4.0\\",\\"markups\\":[],\\"atoms\\":[],\\"cards\\":[],\\"sections\\":[[1,\\"p\\",[[0,[],0,\\"\\"]]]]}",
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"post_revisions": Any<Array>,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"slug": "collection-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Array [
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": null,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": null,
|
||||
"monthly_price_id": null,
|
||||
"name": "Free",
|
||||
"slug": "free",
|
||||
"trial_days": 0,
|
||||
"type": "free",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": null,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": 500,
|
||||
"monthly_price_id": null,
|
||||
"name": "Default Product",
|
||||
"slug": "default-product",
|
||||
"trial_days": 0,
|
||||
"type": "paid",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": 5000,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
],
|
||||
"title": "Collection 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 add and remove collections 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": "3992",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": StringMatching /\\\\/p\\\\/\\[0-9a-f\\]\\{8\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{12\\}/,
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can add and remove collections 5: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
Object {
|
||||
"authors": Any<Array>,
|
||||
"canonical_url": null,
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"collections": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.\\\\d\\{3\\}Z/,
|
||||
"description": null,
|
||||
"feature_image": null,
|
||||
"filter": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"posts": Array [
|
||||
Object {
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"sort_order": 0,
|
||||
},
|
||||
],
|
||||
"title": "Collection to add.",
|
||||
"type": "manual",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.\\\\d\\{3\\}Z/,
|
||||
},
|
||||
],
|
||||
"comment_id": Any<String>,
|
||||
"count": Object {
|
||||
"clicks": 0,
|
||||
"negative_feedback": 0,
|
||||
"positive_feedback": 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": null,
|
||||
"feature_image": null,
|
||||
"feature_image_alt": null,
|
||||
"feature_image_caption": null,
|
||||
"featured": false,
|
||||
"frontmatter": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"mobiledoc": "{\\"version\\":\\"0.3.1\\",\\"ghostVersion\\":\\"4.0\\",\\"markups\\":[],\\"atoms\\":[],\\"cards\\":[],\\"sections\\":[[1,\\"p\\",[[0,[],0,\\"\\"]]]]}",
|
||||
"newsletter": null,
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"post_revisions": Any<Array>,
|
||||
"primary_author": Any<Object>,
|
||||
"primary_tag": Any<Object>,
|
||||
"published_at": null,
|
||||
"slug": "collection-update-test",
|
||||
"status": "draft",
|
||||
"tags": Any<Array>,
|
||||
"tiers": Array [
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": null,
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": null,
|
||||
"monthly_price_id": null,
|
||||
"name": "Free",
|
||||
"slug": "free",
|
||||
"trial_days": 0,
|
||||
"type": "free",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": null,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
Object {
|
||||
"active": true,
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"monthly_price": 500,
|
||||
"monthly_price_id": null,
|
||||
"name": "Default Product",
|
||||
"slug": "default-product",
|
||||
"trial_days": 0,
|
||||
"type": "paid",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"visibility": "public",
|
||||
"welcome_page_url": null,
|
||||
"yearly_price": 5000,
|
||||
"yearly_price_id": null,
|
||||
},
|
||||
],
|
||||
"title": "Collection 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 add and remove collections 6: [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": "3989",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-cache-invalidate": StringMatching /\\\\/p\\\\/\\[0-9a-f\\]\\{8\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{4\\}-\\[0-9a-f\\]\\{12\\}/,
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Posts API Update Can update a post with lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"posts": Array [
|
||||
|
@ -419,6 +419,80 @@ describe('Posts API', function () {
|
||||
|
||||
mobiledocRevisions.length.should.equal(0);
|
||||
});
|
||||
|
||||
it('Can add and remove collections', async function () {
|
||||
const {body: postBody} = await agent
|
||||
.post('/posts/')
|
||||
.body({
|
||||
posts: [{
|
||||
title: 'Collection update test'
|
||||
}]
|
||||
})
|
||||
.expectStatus(201)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign({}, matchPostShallowIncludes, {published_at: null})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag,
|
||||
location: anyLocationFor('posts')
|
||||
});
|
||||
|
||||
const [postResponse] = postBody.posts;
|
||||
|
||||
const {body: {
|
||||
collections: [collectionToAdd]
|
||||
}} = await agent
|
||||
.post('/collections/')
|
||||
.body({
|
||||
collections: [{
|
||||
title: 'Collection to add.'
|
||||
}]
|
||||
});
|
||||
|
||||
const {body: {
|
||||
collections: [collectionToRemove]
|
||||
}} = await agent
|
||||
.post('/collections/')
|
||||
.body({
|
||||
collections: [{
|
||||
title: 'Collection to remove.'
|
||||
}]
|
||||
});
|
||||
|
||||
const collectionMatcher = {
|
||||
id: anyObjectId,
|
||||
created_at: stringMatching(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z/),
|
||||
updated_at: stringMatching(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z/),
|
||||
posts: [{
|
||||
id: anyObjectId
|
||||
}]
|
||||
};
|
||||
|
||||
await agent.put(`/posts/${postResponse.id}/`)
|
||||
.body({posts: [Object.assign({}, postResponse, {collections: [collectionToRemove.id]})]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign({}, matchPostShallowIncludes, {published_at: null}, {collections: [collectionMatcher]})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag,
|
||||
'x-cache-invalidate': stringMatching(/\/p\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
|
||||
});
|
||||
|
||||
await agent.put(`/posts/${postResponse.id}/`)
|
||||
.body({posts: [Object.assign({}, postResponse, {collections: [collectionToAdd.id]})]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
posts: [Object.assign({}, matchPostShallowIncludes, {published_at: null}, {collections: [collectionMatcher]})]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag,
|
||||
'x-cache-invalidate': stringMatching(/\/p\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete', function () {
|
||||
|
@ -23,6 +23,7 @@ class PostsService {
|
||||
this.stats = stats;
|
||||
this.emailService = emailService;
|
||||
this.postsExporter = postsExporter;
|
||||
/** @type {import('@tryghost/collections').CollectionsService} */
|
||||
this.collectionsService = collectionsService;
|
||||
}
|
||||
|
||||
@ -44,7 +45,18 @@ class PostsService {
|
||||
return dto;
|
||||
}
|
||||
|
||||
async editPost(frame) {
|
||||
/**
|
||||
* @typedef {'published_updated' | 'scheduled_updated' | 'draft_updated' | 'unpublished'} EventString
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} frame
|
||||
* @param {object} [options]
|
||||
* @param {(event: EventString, dto: any) => Promise<void> | void} [options.eventHandler] - Called before the editPost method resolves with an event string
|
||||
* @returns
|
||||
*/
|
||||
async editPost(frame, options) {
|
||||
// Make sure the newsletter is matching an active newsletter
|
||||
// Note that this option is simply ignored if the post isn't published or scheduled
|
||||
if (frame.options.newsletter && frame.options.email_segment) {
|
||||
@ -61,6 +73,49 @@ class PostsService {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isSet('collections') && frame.data.posts[0].collections) {
|
||||
const existingCollections = await this.collectionsService.getCollectionsForPost(frame.options.id);
|
||||
for (const collection of frame.data.posts[0].collections) {
|
||||
let collectionId = null;
|
||||
if (typeof collection === 'string') {
|
||||
collectionId = collection;
|
||||
}
|
||||
if (typeof collection?.id === 'string') {
|
||||
collectionId = collection.id;
|
||||
}
|
||||
if (!collectionId) {
|
||||
continue;
|
||||
}
|
||||
const existingCollection = existingCollections.find(c => c.id === collectionId);
|
||||
if (existingCollection) {
|
||||
continue;
|
||||
}
|
||||
const found = await this.collectionsService.getById(collectionId);
|
||||
if (!found) {
|
||||
continue;
|
||||
}
|
||||
if (found.type !== 'manual') {
|
||||
continue;
|
||||
}
|
||||
await this.collectionsService.addPostToCollection(collectionId, {
|
||||
id: frame.options.id,
|
||||
featured: frame.data.posts[0].featured,
|
||||
published_at: frame.data.posts[0].published_at
|
||||
});
|
||||
}
|
||||
for (const existingCollection of existingCollections) {
|
||||
if (frame.data.posts[0].collections.find((item) => {
|
||||
if (typeof item === 'string') {
|
||||
return item === existingCollection.id;
|
||||
}
|
||||
return item.id === existingCollection.id;
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
await this.collectionsService.removePostFromCollection(existingCollection.id, frame.options.id);
|
||||
}
|
||||
}
|
||||
|
||||
const model = await this.models.Post.edit(frame.data.posts[0], frame.options);
|
||||
|
||||
/**Handle newsletter email */
|
||||
@ -82,7 +137,40 @@ class PostsService {
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
const dto = model.toJSON(frame.options);
|
||||
|
||||
if (this.isSet('collections')) {
|
||||
if (frame?.original?.query?.include?.includes('collections') || frame.data.posts[0].collections) {
|
||||
dto.collections = await this.collectionsService.getCollectionsForPost(model.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof options?.eventHandler === 'function') {
|
||||
await options.eventHandler(this.getChanges(model), dto);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
/**
|
||||
* @param {any} model
|
||||
* @returns {EventString}
|
||||
*/
|
||||
getChanges(model) {
|
||||
if (model.get('status') === 'published' && model.wasChanged()) {
|
||||
return 'published_updated';
|
||||
}
|
||||
|
||||
if (model.get('status') === 'draft' && model.previous('status') === 'published') {
|
||||
return 'unpublished';
|
||||
}
|
||||
|
||||
if (model.get('status') === 'draft' && model.previous('status') !== 'published') {
|
||||
return 'draft_updated';
|
||||
}
|
||||
|
||||
if (model.get('status') === 'scheduled' && model.wasChanged()) {
|
||||
return 'scheduled_updated';
|
||||
}
|
||||
}
|
||||
|
||||
#mergeFilters(...filters) {
|
||||
|
Loading…
Reference in New Issue
Block a user