diff --git a/core/server/api/v2/pages.js b/core/server/api/v2/pages.js index e5a0e5f8ed..39db717711 100644 --- a/core/server/api/v2/pages.js +++ b/core/server/api/v2/pages.js @@ -1,4 +1,6 @@ +const common = require('../../lib/common'); const models = require('../../models'); +const ALLOWED_INCLUDES = ['created_by', 'updated_by', 'published_by', 'author', 'tags', 'authors', 'authors.roles']; module.exports = { docName: 'pages', @@ -18,7 +20,7 @@ module.exports = { validation: { options: { include: { - values: ['created_by', 'updated_by', 'published_by', 'author', 'tags', 'authors', 'authors.roles'] + values: ALLOWED_INCLUDES }, formats: { values: models.Post.allowedFormats @@ -29,5 +31,45 @@ module.exports = { query(frame) { return models.Post.findPage(frame.options); } + }, + + read: { + options: [ + 'include', + 'filter', + 'fields', + 'status', + 'formats', + 'debug' + ], + data: [ + 'id', + 'slug', + 'status', + 'uuid' + ], + validation: { + options: { + include: { + values: ALLOWED_INCLUDES + }, + formats: { + values: models.Post.allowedFormats + } + } + }, + permissions: true, + query(frame) { + return models.Post.findOne(frame.data, frame.options) + .then((model) => { + if (!model) { + throw new common.errors.NotFoundError({ + message: common.i18n.t('errors.api.pages.pageNotFound') + }); + } + + return model; + }); + } } }; diff --git a/core/server/translations/en.json b/core/server/translations/en.json index 1615880ce0..f8270401b5 100644 --- a/core/server/translations/en.json +++ b/core/server/translations/en.json @@ -349,6 +349,9 @@ "posts": { "postNotFound": "Post not found." }, + "pages": { + "pageNotFound": "Page not found." + }, "job": { "notFound": "Job not found.", "publishInThePast": "Use the force flag to publish a post in the past." diff --git a/core/server/web/api/v2/content/routes.js b/core/server/web/api/v2/content/routes.js index 8e5163468b..0b8bbd5e32 100644 --- a/core/server/web/api/v2/content/routes.js +++ b/core/server/web/api/v2/content/routes.js @@ -16,6 +16,8 @@ module.exports = function apiRoutes() { // ## Pages router.get('/pages', mw.authenticatePublic, apiv2.http(apiv2.pages.browse)); + router.get('/pages/:id', mw.authenticatePublic, apiv2.http(apiv2.pages.read)); + router.get('/pages/slug/:slug', mw.authenticatePublic, apiv2.http(apiv2.pages.read)); // ## Users router.get('/users', mw.authenticatePublic, apiv2.http(apiv2.users.browse)); diff --git a/core/test/functional/api/v2/content/pages_spec.js b/core/test/functional/api/v2/content/pages_spec.js index bf4cddad25..bad1e33c06 100644 --- a/core/test/functional/api/v2/content/pages_spec.js +++ b/core/test/functional/api/v2/content/pages_spec.js @@ -48,4 +48,28 @@ describe('Pages', function () { should.exist(urlParts.host); }); }); + + it('read page', function () { + const key = localUtils.getValidKey(); + return request.get(localUtils.API.getApiQuery(`pages/${testUtils.DataGenerator.Content.posts[4].id}/?key=${key}`)) + .set('Origin', testUtils.API.getURL()) + .expect('Content-Type', /json/) + .expect('Cache-Control', testUtils.cacheRules.private) + .expect(200) + .then((res) => { + res.headers.vary.should.eql('Accept-Encoding'); + should.exist(res.headers['access-control-allow-origin']); + should.not.exist(res.headers['x-cache-invalidate']); + + const jsonResponse = res.body; + should.exist(jsonResponse.pages); + jsonResponse.pages.should.have.length(1); + + res.body.pages[0].slug.should.eql(testUtils.DataGenerator.Content.posts[4].slug); + + const urlParts = url.parse(res.body.pages[0].url); + should.exist(urlParts.protocol); + should.exist(urlParts.host); + }); + }); });