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:
parent
7904253f62
commit
ffd3ec563a
3 changed files with 47 additions and 8 deletions
|
@ -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
|
// Bookshelf `initialize` - declare a constructor-like method for model creation
|
||||||
initialize: function initialize() {
|
initialize: function initialize() {
|
||||||
var self = this,
|
var self = this,
|
||||||
|
@ -318,10 +323,10 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
||||||
findPage: function findPage(options) {
|
findPage: function findPage(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var self = this,
|
var self = this,
|
||||||
itemCollection = this.forge(null, {context: options.context}),
|
itemCollection = this.forge(null, {context: options.context}),
|
||||||
tableName = _.result(this.prototype, 'tableName'),
|
tableName = _.result(this.prototype, 'tableName'),
|
||||||
allColumns = options.columns;
|
requestedColumns = options.columns;
|
||||||
|
|
||||||
// Set this to true or pass ?debug=true as an API option to get output
|
// Set this to true or pass ?debug=true as an API option to get output
|
||||||
itemCollection.debug = options.debug && process.env.NODE_ENV !== 'production';
|
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);
|
options.withRelated = _.union(options.withRelated, options.include);
|
||||||
|
|
||||||
// Ensure only valid fields/columns are added to query
|
// Ensure only valid fields/columns are added to query
|
||||||
|
// and append default columns to fetch
|
||||||
if (options.columns) {
|
if (options.columns) {
|
||||||
options.columns = _.intersection(options.columns, this.prototype.permittedAttributes());
|
options.columns = _.intersection(options.columns, this.prototype.permittedAttributes());
|
||||||
|
options.columns = _.union(options.columns, this.prototype.defaultColumnsToFetch());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.order) {
|
if (options.order) {
|
||||||
|
@ -355,13 +362,18 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemCollection.fetchPage(options).then(function formatResponse(response) {
|
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
|
// re-add any computed properties that were stripped out before the call to fetchPage
|
||||||
options.columns = allColumns;
|
// pick only requested before returning JSON
|
||||||
data[tableName] = response.collection.toJSON(options);
|
data[tableName] = _.map(models, function transform(model) {
|
||||||
|
return options.columns ? _.pick(model, options.columns) : model;
|
||||||
|
});
|
||||||
data.meta = {pagination: response.pagination};
|
data.meta = {pagination: response.pagination};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -393,6 +393,10 @@ Post = ghostBookshelf.Model.extend({
|
||||||
return this.morphMany('AppField', 'relatable');
|
return this.morphMany('AppField', 'relatable');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
defaultColumnsToFetch: function defaultColumnsToFetch() {
|
||||||
|
return ['id', 'published_at', 'slug', 'author_id'];
|
||||||
|
},
|
||||||
|
|
||||||
toJSON: function toJSON(options) {
|
toJSON: function toJSON(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ var Promise = require('bluebird'),
|
||||||
should = require('should'),
|
should = require('should'),
|
||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
testUtils = require('../../utils'),
|
testUtils = require('../../utils'),
|
||||||
|
configUtils = require('../../utils/configUtils'),
|
||||||
errors = require('../../../server/errors'),
|
errors = require('../../../server/errors'),
|
||||||
db = require('../../../server/data/db'),
|
db = require('../../../server/data/db'),
|
||||||
models = require('../../../server/models'),
|
models = require('../../../server/models'),
|
||||||
|
@ -45,6 +46,16 @@ describe('Post API', function () {
|
||||||
should.exist(PostAPI);
|
should.exist(PostAPI);
|
||||||
|
|
||||||
describe('Browse', function () {
|
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) {
|
it('can fetch all posts with internal context in correct order', function (done) {
|
||||||
PostAPI.browse({context: {internal: true}}).then(function (results) {
|
PostAPI.browse({context: {internal: true}}).then(function (results) {
|
||||||
should.exist(results.posts);
|
should.exist(results.posts);
|
||||||
|
@ -359,6 +370,18 @@ describe('Post API', function () {
|
||||||
}).catch(done);
|
}).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) {
|
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) {
|
PostAPI.browse({context: {user: 1}, status: 'all', limit: 5, fields: 'Slug,Published_At'}).then(function (results) {
|
||||||
should.exist(results.posts);
|
should.exist(results.posts);
|
||||||
|
|
Loading…
Add table
Reference in a new issue