diff --git a/ghost/core/core/server/api/endpoints/collections.js b/ghost/core/core/server/api/endpoints/collections.js index 18b7865513..6922ef6385 100644 --- a/ghost/core/core/server/api/endpoints/collections.js +++ b/ghost/core/core/server/api/endpoints/collections.js @@ -116,9 +116,9 @@ module.exports = { // @NOTE: should have permissions when moving out of Alpha permissions: false, async query(frame) { - const collectionPost = await collectionsService.api.addPost(Object.assign(frame.data.collections[0], { - collection_id: frame.options.id - }), frame.options); + const collectionPost = await collectionsService.api.addPost(frame.options.id, { + id: frame.data.posts[0].id + }); if (!collectionPost) { throw new errors.NotFoundError({ diff --git a/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/collections.js b/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/collections.js index 0751061ff7..6493a26e7f 100644 --- a/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/collections.js +++ b/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/collections.js @@ -1,27 +1,41 @@ /** * - * @param {import('@tryghost/collections').Collection} collection + * @param {import('@tryghost/collections').Collection | object} collection * * @returns {SerializedCollection} */ const mapper = (collection) => { - const json = collection.toJSON(); + let json; + let posts; + if (collection.toJSON) { + json = collection.toJSON(); + posts = json.posts.map((postId, index) => { + return { + id: postId, + sort_order: index + }; + }); + } else { + json = collection; + posts = json.posts.map((post) => { + return { + id: post.id, + sort_order: post.sort_order + }; + }); + } const serialized = { id: json.id, - title: json.title, + title: json.title || null, slug: json.slug, - description: json.description, + description: json.description || null, type: json.type, filter: json.filter, - feature_image: json.featureImage, - created_at: json.createdAt.toISOString().replace(/\d{3}Z$/, '000Z'), - updated_at: json.updatedAt.toISOString().replace(/\d{3}Z$/, '000Z'), - posts: json.posts.map(post => ({ - id: post.id, - title: post.title, - slug: post.slug - })) + feature_image: json.feature_image || json.featureImage || null, + created_at: (json.created_at || json.createdAt).toISOString().replace(/\d{3}Z$/, '000Z'), + updated_at: (json.updated_at || json.updatedAt).toISOString().replace(/\d{3}Z$/, '000Z'), + posts }; return serialized; diff --git a/ghost/core/core/server/services/collections/index.js b/ghost/core/core/server/services/collections/index.js index d4379a68f3..d4a00e27a5 100644 --- a/ghost/core/core/server/services/collections/index.js +++ b/ghost/core/core/server/services/collections/index.js @@ -1,30 +1,24 @@ -const models = require('../../models'); const { CollectionsService, CollectionsRepositoryInMemory } = require('@tryghost/collections'); -const PostsDataRepositoryBookshelf = require('./PostsDataRepositoryBookshelf'); class CollectionsServiceWrapper { api; constructor() { const collectionsRepositoryInMemory = new CollectionsRepositoryInMemory(); - const postsDataRepositoryBookshelf = new PostsDataRepositoryBookshelf({ - Post: models.Post - }); const collectionsService = new CollectionsService({ - collectionsRepository: collectionsRepositoryInMemory, - postsRepository: postsDataRepositoryBookshelf + collectionsRepository: collectionsRepositoryInMemory }); this.api = { browse: collectionsService.getAll.bind(collectionsService), read: collectionsService.getById.bind(collectionsService), - add: collectionsService.save.bind(collectionsService), + add: collectionsService.createCollection.bind(collectionsService), edit: collectionsService.edit.bind(collectionsService), - addPost: collectionsService.addPost.bind(collectionsService), + addPost: collectionsService.addPostToCollection.bind(collectionsService), destroy: collectionsService.destroy.bind(collectionsService) }; } diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/collections.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/collections.test.js.snap index 0ee4778e4a..3b8bd17aee 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/collections.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/collections.test.js.snap @@ -322,12 +322,15 @@ Object { "posts": Array [ Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 0, }, Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 1, }, Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 2, }, ], "title": "Test Collection Edited", @@ -342,7 +345,7 @@ exports[`Collections API edit Can add Posts and append Post to a Collection 2: [ 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": "346", + "content-length": "391", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -364,12 +367,15 @@ Object { "posts": Array [ Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 0, }, Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 1, }, Object { "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": 2, }, ], "title": "Test Collection Edited", @@ -384,7 +390,103 @@ exports[`Collections API edit Can add Posts and append Post to a Collection 4: [ 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": "346", + "content-length": "391", + "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-powered-by": "Express", +} +`; + +exports[`Collections API edit Can add Posts and append Post to a Collection 5: [body] 1`] = ` +Object { + "collections": Array [ + Object { + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "description": null, + "feature_image": null, + "filter": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "posts": Array [ + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + ], + "title": "Test Collection Edited", + "type": "manual", + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + }, + ], +} +`; + +exports[`Collections API edit Can add Posts and append Post to a Collection 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": "440", + "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-powered-by": "Express", +} +`; + +exports[`Collections API edit Can add Posts and append Post to a Collection 7: [body] 1`] = ` +Object { + "collections": Array [ + Object { + "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + "description": null, + "feature_image": null, + "filter": null, + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "posts": Array [ + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + Object { + "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "sort_order": Any, + }, + ], + "title": "Test Collection Edited", + "type": "manual", + "updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, + }, + ], +} +`; + +exports[`Collections API edit Can add Posts and append Post to a Collection 8: [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": "440", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, diff --git a/ghost/core/test/e2e-api/admin/collections.test.js b/ghost/core/test/e2e-api/admin/collections.test.js index e440655d91..94a9345e0b 100644 --- a/ghost/core/test/e2e-api/admin/collections.test.js +++ b/ghost/core/test/e2e-api/admin/collections.test.js @@ -11,7 +11,8 @@ const { anyErrorId, anyLocationFor, anyObjectId, - anyISODateTime + anyISODateTime, + anyNumber } = matchers; const matchCollection = { @@ -24,12 +25,16 @@ const matchCollection = { * * @param {number} postCount */ -const buildMatcher = (postCount) => { +const buildMatcher = (postCount, opts = {}) => { + let obj = { + id: anyObjectId + }; + if (opts.withSortOrder) { + obj.sort_order = anyNumber; + } return { ...matchCollection, - posts: Array(postCount).fill({ - id: anyObjectId - }) + posts: Array(postCount).fill(obj) }; }; @@ -234,9 +239,7 @@ describe('Collections API', function () { etag: anyEtag }) .matchBodySnapshot({ - posts: [{ - id: anyObjectId - }] + collections: [buildMatcher(4, {withSortOrder: true})] }); // verify the posts are persisted across requests @@ -248,7 +251,7 @@ describe('Collections API', function () { etag: anyEtag }) .matchBodySnapshot({ - collections: [buildMatcher(3)] + collections: [buildMatcher(4, {withSortOrder: true})] }); assert.equal(readResponse.body.collections[0].posts.length, 4, 'Post should have been added to a Collection');