mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
add small permission improvements
no issue - do not check client type in auth middleware - offer filtering for findAll function in base - add isInternalContext to base model
This commit is contained in:
parent
2744fed5d8
commit
f644d99460
@ -113,7 +113,7 @@ db = {
|
|||||||
*/
|
*/
|
||||||
deleteAllContent: function (options) {
|
deleteAllContent: function (options) {
|
||||||
var tasks,
|
var tasks,
|
||||||
queryOpts = {columns: 'id'};
|
queryOpts = {columns: 'id', context: {internal: true}};
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ auth = {
|
|||||||
delete req.body.client_id;
|
delete req.body.client_id;
|
||||||
delete req.body.client_secret;
|
delete req.body.client_secret;
|
||||||
|
|
||||||
if (!client || client.type !== 'ua') {
|
if (!client) {
|
||||||
errors.logError(
|
errors.logError(
|
||||||
i18n.t('errors.middleware.auth.clientAuthenticationFailed'),
|
i18n.t('errors.middleware.auth.clientAuthenticationFailed'),
|
||||||
i18n.t('errors.middleware.auth.clientCredentialsNotValid'),
|
i18n.t('errors.middleware.auth.clientCredentialsNotValid'),
|
||||||
|
@ -233,14 +233,24 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* ### Find All
|
* ### Find All
|
||||||
* Naive find all fetches all the data for a particular model
|
* Fetches all the data for a particular model
|
||||||
* @param {Object} options (optional)
|
* @param {Object} options (optional)
|
||||||
* @return {Promise(ghostBookshelf.Collection)} Collection of all Models
|
* @return {Promise(ghostBookshelf.Collection)} Collection of all Models
|
||||||
*/
|
*/
|
||||||
findAll: function findAll(options) {
|
findAll: function findAll(options) {
|
||||||
options = this.filterOptions(options, 'findAll');
|
options = this.filterOptions(options, 'findAll');
|
||||||
options.withRelated = _.union(options.withRelated, options.include);
|
options.withRelated = _.union(options.withRelated, options.include);
|
||||||
return this.forge().fetchAll(options).then(function then(result) {
|
|
||||||
|
var itemCollection = this.forge(null, {context: options.context});
|
||||||
|
|
||||||
|
// transforms fictive keywords like 'all' (status:all) into correct allowed values
|
||||||
|
if (this.processOptions) {
|
||||||
|
this.processOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
itemCollection.applyDefaultAndCustomFilters(options);
|
||||||
|
|
||||||
|
return itemCollection.fetchAll(options).then(function then(result) {
|
||||||
if (options.include) {
|
if (options.include) {
|
||||||
_.each(result.models, function each(item) {
|
_.each(result.models, function each(item) {
|
||||||
item.include = options.include;
|
item.include = options.include;
|
||||||
@ -290,7 +300,7 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
|||||||
this.processOptions(options);
|
this.processOptions(options);
|
||||||
|
|
||||||
// Add Filter behaviour
|
// Add Filter behaviour
|
||||||
itemCollection.applyFilters(options);
|
itemCollection.applyDefaultAndCustomFilters(options);
|
||||||
|
|
||||||
// Handle related objects
|
// Handle related objects
|
||||||
// TODO: this should just be done for all methods @ the API level
|
// TODO: this should just be done for all methods @ the API level
|
||||||
@ -306,7 +316,6 @@ ghostBookshelf.Model = ghostBookshelf.Model.extend({
|
|||||||
} else {
|
} else {
|
||||||
options.order = self.orderDefaultOptions();
|
options.order = self.orderDefaultOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemCollection.fetchPage(options).then(function formatResponse(response) {
|
return itemCollection.fetchPage(options).then(function formatResponse(response) {
|
||||||
var data = {};
|
var data = {};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ module.exports = function (Bookshelf) {
|
|||||||
* Cached copy of the context setup for this model instance
|
* Cached copy of the context setup for this model instance
|
||||||
*/
|
*/
|
||||||
_context: null,
|
_context: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Is Public Context?
|
* ## Is Public Context?
|
||||||
* A helper to determine if this is a public request or not
|
* A helper to determine if this is a public request or not
|
||||||
@ -18,6 +19,10 @@ module.exports = function (Bookshelf) {
|
|||||||
*/
|
*/
|
||||||
isPublicContext: function isPublicContext() {
|
isPublicContext: function isPublicContext() {
|
||||||
return !!(this._context && this._context.public);
|
return !!(this._context && this._context.public);
|
||||||
|
},
|
||||||
|
|
||||||
|
isInternalContext: function isInternalContext() {
|
||||||
|
return !!(this._context && this._context.internal);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -118,6 +118,7 @@ filter = function filter(Bookshelf) {
|
|||||||
.query('join', 'users as author', 'author.id', '=', 'posts.author_id');
|
.query('join', 'users as author', 'author.id', '=', 'posts.author_id');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## fetchAndCombineFilters
|
* ## fetchAndCombineFilters
|
||||||
* Helper method, uses the combineFilters util to apply filters to the current model instance
|
* Helper method, uses the combineFilters util to apply filters to the current model instance
|
||||||
@ -137,6 +138,7 @@ filter = function filter(Bookshelf) {
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Apply Filters
|
* ## Apply Filters
|
||||||
* Method which makes the necessary query builder calls (through knex) for the filters set
|
* Method which makes the necessary query builder calls (through knex) for the filters set
|
||||||
@ -144,7 +146,7 @@ filter = function filter(Bookshelf) {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @returns {Bookshelf.Model}
|
* @returns {Bookshelf.Model}
|
||||||
*/
|
*/
|
||||||
applyFilters: function applyFilters(options) {
|
applyDefaultAndCustomFilters: function applyDefaultAndCustomFilters(options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// @TODO figure out a better place/way to trigger loading filters
|
// @TODO figure out a better place/way to trigger loading filters
|
||||||
|
@ -394,6 +394,10 @@ Post = ghostBookshelf.Model.extend({
|
|||||||
return this.isPublicContext() ? 'status:published' : null;
|
return this.isPublicContext() ? 'status:published' : null;
|
||||||
},
|
},
|
||||||
defaultFilters: function defaultFilters() {
|
defaultFilters: function defaultFilters() {
|
||||||
|
if (this.isInternalContext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return this.isPublicContext() ? 'page:false' : 'page:false+status:published';
|
return this.isPublicContext() ? 'page:false' : 'page:false+status:published';
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@ -458,7 +462,7 @@ Post = ghostBookshelf.Model.extend({
|
|||||||
validOptions = {
|
validOptions = {
|
||||||
findOne: ['columns', 'importing', 'withRelated', 'require'],
|
findOne: ['columns', 'importing', 'withRelated', 'require'],
|
||||||
findPage: ['page', 'limit', 'columns', 'filter', 'order', 'status', 'staticPages'],
|
findPage: ['page', 'limit', 'columns', 'filter', 'order', 'status', 'staticPages'],
|
||||||
findAll: ['columns'],
|
findAll: ['columns', 'filter'],
|
||||||
add: ['importing']
|
add: ['importing']
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -636,6 +640,7 @@ Post = ghostBookshelf.Model.extend({
|
|||||||
if (_.isNumber(postModelOrId) || _.isString(postModelOrId)) {
|
if (_.isNumber(postModelOrId) || _.isString(postModelOrId)) {
|
||||||
// Grab the original args without the first one
|
// Grab the original args without the first one
|
||||||
origArgs = _.toArray(arguments).slice(1);
|
origArgs = _.toArray(arguments).slice(1);
|
||||||
|
|
||||||
// Get the actual post model
|
// Get the actual post model
|
||||||
return this.findOne({id: postModelOrId, status: 'all'}).then(function then(foundPostModel) {
|
return this.findOne({id: postModelOrId, status: 'all'}).then(function then(foundPostModel) {
|
||||||
// Build up the original args but substitute with actual model
|
// Build up the original args but substitute with actual model
|
||||||
|
@ -170,9 +170,15 @@ User = ghostBookshelf.Model.extend({
|
|||||||
return role.get('name') === roleName;
|
return role.get('name') === roleName;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
enforcedFilters: function enforcedFilters() {
|
enforcedFilters: function enforcedFilters() {
|
||||||
|
if (this.isInternalContext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return this.isPublicContext() ? 'status:[' + activeStates.join(',') + ']' : null;
|
return this.isPublicContext() ? 'status:[' + activeStates.join(',') + ']' : null;
|
||||||
},
|
},
|
||||||
|
|
||||||
defaultFilters: function defaultFilters() {
|
defaultFilters: function defaultFilters() {
|
||||||
return this.isPublicContext() ? null : 'status:[' + activeStates.join(',') + ']';
|
return this.isPublicContext() ? null : 'status:[' + activeStates.join(',') + ']';
|
||||||
}
|
}
|
||||||
@ -235,7 +241,8 @@ User = ghostBookshelf.Model.extend({
|
|||||||
findOne: ['withRelated', 'status'],
|
findOne: ['withRelated', 'status'],
|
||||||
setup: ['id'],
|
setup: ['id'],
|
||||||
edit: ['withRelated', 'id'],
|
edit: ['withRelated', 'id'],
|
||||||
findPage: ['page', 'limit', 'columns', 'filter', 'order', 'status']
|
findPage: ['page', 'limit', 'columns', 'filter', 'order', 'status'],
|
||||||
|
findAll: ['filter']
|
||||||
};
|
};
|
||||||
|
|
||||||
if (validOptions[methodName]) {
|
if (validOptions[methodName]) {
|
||||||
|
@ -139,12 +139,13 @@ describe('Database Migration (special functions)', function () {
|
|||||||
|
|
||||||
describe('Populate', function () {
|
describe('Populate', function () {
|
||||||
beforeEach(testUtils.setup());
|
beforeEach(testUtils.setup());
|
||||||
|
|
||||||
it('should populate all fixtures correctly', function (done) {
|
it('should populate all fixtures correctly', function (done) {
|
||||||
fixtures.populate(loggerStub).then(function () {
|
fixtures.populate(loggerStub).then(function () {
|
||||||
var props = {
|
var props = {
|
||||||
posts: Models.Post.findAll({include: ['tags']}),
|
posts: Models.Post.findAll({include: ['tags']}),
|
||||||
tags: Models.Tag.findAll(),
|
tags: Models.Tag.findAll(),
|
||||||
users: Models.User.findAll({include: ['roles']}),
|
users: Models.User.findAll({filter: 'status:inactive', context: {internal:true}, include: ['roles']}),
|
||||||
clients: Models.Client.findAll(),
|
clients: Models.Client.findAll(),
|
||||||
roles: Models.Role.findAll(),
|
roles: Models.Role.findAll(),
|
||||||
permissions: Models.Permission.findAll({include: ['roles']})
|
permissions: Models.Permission.findAll({include: ['roles']})
|
||||||
@ -181,6 +182,7 @@ describe('Database Migration (special functions)', function () {
|
|||||||
should.exist(result.users);
|
should.exist(result.users);
|
||||||
result.users.length.should.eql(1);
|
result.users.length.should.eql(1);
|
||||||
result.users.at(0).get('name').should.eql('Ghost Owner');
|
result.users.at(0).get('name').should.eql('Ghost Owner');
|
||||||
|
result.users.at(0).get('status').should.eql('inactive');
|
||||||
result.users.at(0).related('roles').length.should.eql(1);
|
result.users.at(0).related('roles').length.should.eql(1);
|
||||||
result.users.at(0).related('roles').at(0).get('name').should.eql('Owner');
|
result.users.at(0).related('roles').at(0).get('name').should.eql('Owner');
|
||||||
|
|
||||||
|
@ -1324,14 +1324,14 @@ describe('Post Model', function () {
|
|||||||
// We're going to delete all posts by user 1
|
// We're going to delete all posts by user 1
|
||||||
var authorData = {id: 1};
|
var authorData = {id: 1};
|
||||||
|
|
||||||
PostModel.findAll().then(function (found) {
|
PostModel.findAll({context:{internal:true}}).then(function (found) {
|
||||||
// There are 50 posts to begin with
|
// There are 50 posts to begin with
|
||||||
found.length.should.equal(50);
|
found.length.should.equal(50);
|
||||||
return PostModel.destroyByAuthor(authorData);
|
return PostModel.destroyByAuthor(authorData);
|
||||||
}).then(function (results) {
|
}).then(function (results) {
|
||||||
// User 1 has 13 posts in the database
|
// User 1 has 13 posts in the database
|
||||||
results.length.should.equal(13);
|
results.length.should.equal(13);
|
||||||
return PostModel.findAll();
|
return PostModel.findAll({context:{internal:true}});
|
||||||
}).then(function (found) {
|
}).then(function (found) {
|
||||||
// Only 37 should remain
|
// Only 37 should remain
|
||||||
found.length.should.equal(37);
|
found.length.should.equal(37);
|
||||||
|
@ -153,7 +153,7 @@ describe('Filter', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Apply Filters', function () {
|
describe('Apply Default and Custom Filters', function () {
|
||||||
var fetchSpy,
|
var fetchSpy,
|
||||||
restoreGQL,
|
restoreGQL,
|
||||||
filterGQL;
|
filterGQL;
|
||||||
@ -174,7 +174,7 @@ describe('Filter', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call fetchAndCombineFilters if _filters not set', function () {
|
it('should call fetchAndCombineFilters if _filters not set', function () {
|
||||||
var result = ghostBookshelf.Model.prototype.applyFilters();
|
var result = ghostBookshelf.Model.prototype.applyDefaultAndCustomFilters();
|
||||||
|
|
||||||
fetchSpy.calledOnce.should.be.true();
|
fetchSpy.calledOnce.should.be.true();
|
||||||
should(result._filters).be.null();
|
should(result._filters).be.null();
|
||||||
@ -183,7 +183,7 @@ describe('Filter', function () {
|
|||||||
it('should NOT call fetchAndCombineFilters if _filters IS set', function () {
|
it('should NOT call fetchAndCombineFilters if _filters IS set', function () {
|
||||||
ghostBookshelf.Model.prototype._filters = 'test';
|
ghostBookshelf.Model.prototype._filters = 'test';
|
||||||
|
|
||||||
var result = ghostBookshelf.Model.prototype.applyFilters();
|
var result = ghostBookshelf.Model.prototype.applyDefaultAndCustomFilters();
|
||||||
|
|
||||||
fetchSpy.called.should.be.false();
|
fetchSpy.called.should.be.false();
|
||||||
result._filters.should.eql('test');
|
result._filters.should.eql('test');
|
||||||
@ -193,7 +193,7 @@ describe('Filter', function () {
|
|||||||
ghostBookshelf.Model.prototype._filters = {statements: [
|
ghostBookshelf.Model.prototype._filters = {statements: [
|
||||||
{prop: 'title', op: '=', value: 'Hello Word'}
|
{prop: 'title', op: '=', value: 'Hello Word'}
|
||||||
]};
|
]};
|
||||||
ghostBookshelf.Model.prototype.applyFilters();
|
ghostBookshelf.Model.prototype.applyDefaultAndCustomFilters();
|
||||||
|
|
||||||
fetchSpy.called.should.be.false();
|
fetchSpy.called.should.be.false();
|
||||||
filterGQL.knexify.called.should.be.true();
|
filterGQL.knexify.called.should.be.true();
|
||||||
@ -208,7 +208,7 @@ describe('Filter', function () {
|
|||||||
{prop: 'tags', op: 'IN', value: ['photo', 'video']}
|
{prop: 'tags', op: 'IN', value: ['photo', 'video']}
|
||||||
]};
|
]};
|
||||||
|
|
||||||
ghostBookshelf.Model.prototype.applyFilters();
|
ghostBookshelf.Model.prototype.applyDefaultAndCustomFilters();
|
||||||
filterGQL.json.printStatements.calledOnce.should.be.true();
|
filterGQL.json.printStatements.calledOnce.should.be.true();
|
||||||
filterGQL.json.printStatements.firstCall.args[0].should.eql([
|
filterGQL.json.printStatements.firstCall.args[0].should.eql([
|
||||||
{prop: 'tags', op: 'IN', value: ['photo', 'video']}
|
{prop: 'tags', op: 'IN', value: ['photo', 'video']}
|
||||||
|
Loading…
Reference in New Issue
Block a user