0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

fix: "url" field is undefined when restricting returned fields (#7089)

closes #6625

- "url" and "author" fields depend on {id, published_at, slug, author_id} to construct post url.
- implemented a generic solution by defining defaultColumnsToFetch() in
  base class for models.
- findPage() calls defaultColumnsToFetch() before loading models
- results are transformed by filtering out additional properties to return just the requested fields
- Added a test case to check for url and author fields
- Renamed allColumns as requestedColumns and used _.map instead of Promise.map
This commit is contained in:
Vijay Kandy 2016-07-18 14:21:47 -06:00 committed by Katharina Irrgang
parent 7904253f62
commit ffd3ec563a
3 changed files with 47 additions and 8 deletions

View file

@ -65,6 +65,11 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
};
},
// When loading an instance, subclasses can specify default to fetch
defaultColumnsToFetch: function defaultColumnsToFetch() {
return [];
},
// Bookshelf `initialize` - declare a constructor-like method for model creation
initialize: function initialize() {
var self = this,
@ -318,10 +323,10 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
findPage: function findPage(options) {
options = options || {};
var self = this,
itemCollection = this.forge(null, {context: options.context}),
tableName = _.result(this.prototype, 'tableName'),
allColumns = options.columns;
var self = this,
itemCollection = this.forge(null, {context: options.context}),
tableName = _.result(this.prototype, 'tableName'),
requestedColumns = options.columns;
// Set this to true or pass ?debug=true as an API option to get output
itemCollection.debug = options.debug && process.env.NODE_ENV !== 'production';
@ -342,8 +347,10 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
options.withRelated = _.union(options.withRelated, options.include);
// Ensure only valid fields/columns are added to query
// and append default columns to fetch
if (options.columns) {
options.columns = _.intersection(options.columns, this.prototype.permittedAttributes());
options.columns = _.union(options.columns, this.prototype.defaultColumnsToFetch());
}
if (options.order) {
@ -355,13 +362,18 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
}
return itemCollection.fetchPage(options).then(function formatResponse(response) {
var data = {};
var data = {},
models = [];
options.columns = requestedColumns;
models = response.collection.toJSON(options);
// re-add any computed properties that were stripped out before the call to fetchPage
options.columns = allColumns;
data[tableName] = response.collection.toJSON(options);
// pick only requested before returning JSON
data[tableName] = _.map(models, function transform(model) {
return options.columns ? _.pick(model, options.columns) : model;
});
data.meta = {pagination: response.pagination};
return data;
});
},

View file

@ -393,6 +393,10 @@ Post = ghostBookshelf.Model.extend({
return this.morphMany('AppField', 'relatable');
},
defaultColumnsToFetch: function defaultColumnsToFetch() {
return ['id', 'published_at', 'slug', 'author_id'];
},
toJSON: function toJSON(options) {
options = options || {};

View file

@ -2,6 +2,7 @@ var Promise = require('bluebird'),
should = require('should'),
_ = require('lodash'),
testUtils = require('../../utils'),
configUtils = require('../../utils/configUtils'),
errors = require('../../../server/errors'),
db = require('../../../server/data/db'),
models = require('../../../server/models'),
@ -45,6 +46,16 @@ describe('Post API', function () {
should.exist(PostAPI);
describe('Browse', function () {
beforeEach(function () {
configUtils.set({theme: {
permalinks: '/:slug/'
}});
});
afterEach(function () {
configUtils.restore();
});
it('can fetch all posts with internal context in correct order', function (done) {
PostAPI.browse({context: {internal: true}}).then(function (results) {
should.exist(results.posts);
@ -359,6 +370,18 @@ describe('Post API', function () {
}).catch(done);
});
it('with context.user can fetch url and author fields', function (done) {
PostAPI.browse({context: {user: 1}, status: 'all', limit: 5}).then(function (results) {
should.exist(results.posts);
should.exist(results.posts[0].url);
should.notEqual(results.posts[0].url, 'undefined');
should.exist(results.posts[0].author);
done();
}).catch(done);
});
it('with context.user can fetch multiple fields and be case insensitive', function (done) {
PostAPI.browse({context: {user: 1}, status: 'all', limit: 5, fields: 'Slug,Published_At'}).then(function (results) {
should.exist(results.posts);