mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Changed preview controller to support v0.1 and v2
refs #9866 - invent preview api, but only used internally - the idea of a preview api is definitiely reaslistic and came up in the past a couple of times - by that we don't have to differentiate between pages or posts controller - still support v0.1 - preview controller is not registered for http, only internal handling
This commit is contained in:
parent
dcf6c0483c
commit
e302be2749
7 changed files with 237 additions and 101 deletions
|
@ -65,5 +65,9 @@ module.exports = {
|
|||
|
||||
get users() {
|
||||
return shared.pipeline(require('./users'), localUtils);
|
||||
},
|
||||
|
||||
get preview() {
|
||||
return shared.pipeline(require('./preview'), localUtils);
|
||||
}
|
||||
};
|
||||
|
|
41
core/server/api/v2/preview.js
Normal file
41
core/server/api/v2/preview.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
const common = require('../../lib/common');
|
||||
const models = require('../../models');
|
||||
const ALLOWED_INCLUDES = ['author', 'authors', 'tags'];
|
||||
|
||||
module.exports = {
|
||||
docName: 'preview',
|
||||
|
||||
read: {
|
||||
permissions: true,
|
||||
options: [
|
||||
'include'
|
||||
],
|
||||
data: [
|
||||
'uuid'
|
||||
],
|
||||
validation: {
|
||||
options: {
|
||||
include: {
|
||||
values: ALLOWED_INCLUDES
|
||||
}
|
||||
},
|
||||
data: {
|
||||
uuid: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
},
|
||||
query(frame) {
|
||||
return models.Post.findOne(Object.assign({status: 'all'}, frame.data), frame.options)
|
||||
.then((model) => {
|
||||
if (!model) {
|
||||
throw new common.errors.NotFoundError({
|
||||
message: common.i18n.t('errors.api.posts.postNotFound')
|
||||
});
|
||||
}
|
||||
|
||||
return model;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
|
@ -53,5 +53,9 @@ module.exports = {
|
|||
|
||||
get users() {
|
||||
return require('./users');
|
||||
},
|
||||
|
||||
get preview() {
|
||||
return require('./preview');
|
||||
}
|
||||
};
|
||||
|
|
7
core/server/api/v2/utils/serializers/output/preview.js
Normal file
7
core/server/api/v2/utils/serializers/output/preview.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
all(model, apiConfig, frame) {
|
||||
frame.response = {
|
||||
preview: [model.toJSON(frame.options)]
|
||||
};
|
||||
}
|
||||
};
|
|
@ -19,7 +19,8 @@ class PreviewRouter extends ParentRouter {
|
|||
|
||||
_prepareContext(req, res, next) {
|
||||
res.routerOptions = {
|
||||
type: 'entry'
|
||||
type: 'entry',
|
||||
resourceType: 'preview'
|
||||
};
|
||||
|
||||
next();
|
||||
|
|
|
@ -14,20 +14,20 @@ module.exports = function previewController(req, res, next) {
|
|||
include: 'author,authors,tags'
|
||||
};
|
||||
|
||||
let resourceType = res.routerOptions.resourceType;
|
||||
|
||||
/**
|
||||
* @TODO:
|
||||
*
|
||||
* We actually need to differentiate here between pages and posts controller for v2.
|
||||
* Currently this API call is without context object and it works out of the box, because the v2 serializer
|
||||
* only forces `page:true|false` if you send a content key.
|
||||
*
|
||||
* It's also a little tricky, because the v0.1 has no pages controller.
|
||||
* Furthermore, the preview router is used for pages and posts and we just receive a uuid. How to know
|
||||
* which controller to call? pages or posts?
|
||||
* Remove fallback to posts if we drop v0.1.
|
||||
*/
|
||||
api.posts.read(params)
|
||||
if (!api[resourceType]) {
|
||||
resourceType = 'posts';
|
||||
}
|
||||
|
||||
api[resourceType]
|
||||
.read(params)
|
||||
.then(function then(result) {
|
||||
const post = result.posts[0];
|
||||
const post = result[resourceType][0];
|
||||
|
||||
if (!post) {
|
||||
return next();
|
||||
|
|
|
@ -28,115 +28,194 @@ describe('Unit - services/routing/controllers/preview', function () {
|
|||
configUtils.restore();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
post = testUtils.DataGenerator.forKnex.createPost({status: 'draft'});
|
||||
describe('v0.1', function () {
|
||||
beforeEach(function () {
|
||||
post = testUtils.DataGenerator.forKnex.createPost({status: 'draft'});
|
||||
|
||||
apiResponse = {
|
||||
posts: [post]
|
||||
};
|
||||
apiResponse = {
|
||||
posts: [post]
|
||||
};
|
||||
|
||||
req = {
|
||||
path: '/',
|
||||
params: {
|
||||
uuid: 'something'
|
||||
},
|
||||
route: {}
|
||||
};
|
||||
req = {
|
||||
path: '/',
|
||||
params: {
|
||||
uuid: 'something'
|
||||
},
|
||||
route: {}
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
apiVersion: 'v0.1'
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy(),
|
||||
set: sinon.spy()
|
||||
};
|
||||
res = {
|
||||
routerOptions: {
|
||||
resourceType: 'preview'
|
||||
},
|
||||
locals: {
|
||||
apiVersion: 'v0.1'
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy(),
|
||||
set: sinon.spy()
|
||||
};
|
||||
|
||||
secureStub = sandbox.stub();
|
||||
renderStub = sandbox.stub();
|
||||
secureStub = sandbox.stub();
|
||||
renderStub = sandbox.stub();
|
||||
|
||||
sandbox.stub(urlService.utils, 'redirectToAdmin');
|
||||
sandbox.stub(urlService.utils, 'redirect301');
|
||||
sandbox.stub(urlService, 'getUrlByResourceId');
|
||||
sandbox.stub(urlService.utils, 'redirectToAdmin');
|
||||
sandbox.stub(urlService.utils, 'redirect301');
|
||||
sandbox.stub(urlService, 'getUrlByResourceId');
|
||||
|
||||
sandbox.stub(helpers, 'secure').get(function () {
|
||||
return secureStub;
|
||||
sandbox.stub(helpers, 'secure').get(function () {
|
||||
return secureStub;
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderEntry').get(function () {
|
||||
return renderStub;
|
||||
});
|
||||
|
||||
sandbox.stub(filters, 'doFilter');
|
||||
|
||||
sandbox.stub(api.posts, 'read').withArgs({
|
||||
uuid: req.params.uuid,
|
||||
status: 'all',
|
||||
include: 'author,authors,tags'
|
||||
}).callsFake(function () {
|
||||
return Promise.resolve(apiResponse);
|
||||
});
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderEntry').get(function () {
|
||||
return renderStub;
|
||||
it('should render post', function (done) {
|
||||
filters.doFilter.withArgs('prePostsRender', post, res.locals).resolves();
|
||||
|
||||
helpers.renderEntry.callsFake(function () {
|
||||
renderStub.called.should.be.true();
|
||||
secureStub.called.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
|
||||
sandbox.stub(filters, 'doFilter');
|
||||
it('should call next if post is not found', function (done) {
|
||||
apiResponse = {posts: []};
|
||||
|
||||
sandbox.stub(api.posts, 'read').withArgs({
|
||||
uuid: req.params.uuid,
|
||||
status: 'all',
|
||||
include: 'author,authors,tags'
|
||||
}).callsFake(function () {
|
||||
return Promise.resolve(apiResponse);
|
||||
controllers.preview(req, res, function (err) {
|
||||
should.not.exist(err);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call redirect if post is published', function (done) {
|
||||
post.status = 'published';
|
||||
urlService.getUrlByResourceId.withArgs(post.id).returns('/something/');
|
||||
|
||||
urlService.utils.redirect301.callsFake(function (res, postUrl) {
|
||||
postUrl.should.eql('/something/');
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should call redirect if /edit/ (options param) is detected', function (done) {
|
||||
req.params.options = 'edit';
|
||||
|
||||
urlService.utils.redirectToAdmin.callsFake(function (statusCode, res, editorUrl) {
|
||||
statusCode.should.eql(302);
|
||||
editorUrl.should.eql(EDITOR_URL + post.id);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should call next for unknown options param detected', function (done) {
|
||||
req.params.options = 'abcde';
|
||||
|
||||
controllers.preview(req, res, function (err) {
|
||||
should.not.exist(err);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should render post', function (done) {
|
||||
filters.doFilter.withArgs('prePostsRender', post, res.locals).resolves();
|
||||
describe('v2', function () {
|
||||
let previewStub;
|
||||
|
||||
helpers.renderEntry.callsFake(function () {
|
||||
renderStub.called.should.be.true();
|
||||
secureStub.called.should.be.true();
|
||||
done();
|
||||
beforeEach(function () {
|
||||
post = testUtils.DataGenerator.forKnex.createPost({status: 'draft'});
|
||||
|
||||
apiResponse = {
|
||||
preview: [post]
|
||||
};
|
||||
|
||||
req = {
|
||||
path: '/',
|
||||
params: {
|
||||
uuid: 'something'
|
||||
},
|
||||
route: {}
|
||||
};
|
||||
|
||||
res = {
|
||||
routerOptions: {
|
||||
resourceType: 'preview'
|
||||
},
|
||||
locals: {
|
||||
apiVersion: 'v2'
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy(),
|
||||
set: sinon.spy()
|
||||
};
|
||||
|
||||
secureStub = sandbox.stub();
|
||||
renderStub = sandbox.stub();
|
||||
|
||||
sandbox.stub(urlService.utils, 'redirectToAdmin');
|
||||
sandbox.stub(urlService.utils, 'redirect301');
|
||||
sandbox.stub(urlService, 'getUrlByResourceId');
|
||||
|
||||
sandbox.stub(helpers, 'secure').get(function () {
|
||||
return secureStub;
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderEntry').get(function () {
|
||||
return renderStub;
|
||||
});
|
||||
|
||||
sandbox.stub(filters, 'doFilter');
|
||||
|
||||
previewStub = sandbox.stub();
|
||||
previewStub.withArgs({
|
||||
uuid: req.params.uuid,
|
||||
status: 'all',
|
||||
include: 'author,authors,tags'
|
||||
}).resolves(apiResponse);
|
||||
|
||||
sandbox.stub(api.v2, 'preview').get(() => {
|
||||
return {
|
||||
read: previewStub
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
it('should render post', function (done) {
|
||||
filters.doFilter.withArgs('prePostsRender', post, res.locals).resolves();
|
||||
|
||||
it('should call next if post is not found', function (done) {
|
||||
apiResponse = {posts: []};
|
||||
helpers.renderEntry.callsFake(function () {
|
||||
renderStub.called.should.be.true();
|
||||
secureStub.called.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, function (err) {
|
||||
should.not.exist(err);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call redirect if post is published', function (done) {
|
||||
post.status = 'published';
|
||||
urlService.getUrlByResourceId.withArgs(post.id).returns('/something/');
|
||||
|
||||
urlService.utils.redirect301.callsFake(function (res, postUrl) {
|
||||
postUrl.should.eql('/something/');
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should call redirect if /edit/ (options param) is detected', function (done) {
|
||||
req.params.options = 'edit';
|
||||
|
||||
urlService.utils.redirectToAdmin.callsFake(function (statusCode, res, editorUrl) {
|
||||
statusCode.should.eql(302);
|
||||
editorUrl.should.eql(EDITOR_URL + post.id);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should call next for unknown options param detected', function (done) {
|
||||
req.params.options = 'abcde';
|
||||
|
||||
controllers.preview(req, res, function (err) {
|
||||
should.not.exist(err);
|
||||
renderStub.called.should.be.false();
|
||||
secureStub.called.should.be.false();
|
||||
done();
|
||||
controllers.preview(req, res, failTest(done));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue