diff --git a/core/server/api/posts.js b/core/server/api/posts.js index fc85251db4..4f9caaa9f7 100644 --- a/core/server/api/posts.js +++ b/core/server/api/posts.js @@ -82,7 +82,7 @@ posts = { var self = this, include; - return canThis(self.user).edit.post(postData.id).then(function () { + return canThis(this).edit.post(postData.id).then(function () { return checkPostData(postData).then(function (checkedPostData) { if (postData.include) { @@ -115,7 +115,7 @@ posts = { include; // **returns:** a promise for the resulting post in a json object - return canThis(this.user).create.post().then(function () { + return canThis(this).create.post().then(function () { return checkPostData(postData).then(function (checkedPostData) { if (postData.include) { include = prepareInclude(postData.include); @@ -141,7 +141,7 @@ posts = { destroy: function destroy(args) { var self = this; // **returns:** a promise for a json response with the id of the deleted post - return canThis(this.user).remove.post(args.id).then(function () { + return canThis(this).remove.post(args.id).then(function () { // TODO: Would it be good to get rid of .call()? return posts.read.call({user: self.user}, {id : args.id, status: 'all'}).then(function (result) { return dataProvider.Post.destroy(args.id).then(function () { @@ -165,7 +165,7 @@ posts = { // **takes:** a string to generate the slug from generateSlug: function generateSlug(args) { - return canThis(this.user).slug.post().then(function () { + return canThis(this).slug.post().then(function () { return dataProvider.Base.Model.generateSlug(dataProvider.Post, args.title, {status: 'all'}).then(function (slug) { if (slug) { return slug; diff --git a/core/server/models/post.js b/core/server/models/post.js index e0e246efc2..58ffe7648b 100644 --- a/core/server/models/post.js +++ b/core/server/models/post.js @@ -473,21 +473,31 @@ Post = ghostBookshelf.Model.extend({ }); }, - permissable: function (postModelOrId, context) { + permissable: function (postModelOrId, context, loadedPermissions, hasUserPermission, hasAppPermission) { var self = this, - userId = context.user, - postModel = postModelOrId; + postModel = postModelOrId, + origArgs; // If we passed in an id instead of a model, get the model // then check the permissions if (_.isNumber(postModelOrId) || _.isString(postModelOrId)) { + // Grab the original args without the first one + origArgs = _.toArray(arguments).slice(1); + // Get the actual post model return this.findOne({id: postModelOrId, status: 'all'}).then(function (foundPostModel) { - return self.permissable(foundPostModel, context); + // Build up the original args but substitute with actual model + var newArgs = [foundPostModel].concat(origArgs); + + return self.permissable.apply(self, newArgs); }, errors.logAndThrowError); } - // If this is the author of the post, allow it. - if (postModel && userId === postModel.get('author_id')) { + if (postModel) { + // If this is the author of the post, allow it. + hasUserPermission = hasUserPermission || context.user === postModel.get('author_id'); + } + + if (hasUserPermission && hasAppPermission) { return when.resolve(); } diff --git a/core/server/models/user.js b/core/server/models/user.js index 7dec00fad4..6651aca802 100644 --- a/core/server/models/user.js +++ b/core/server/models/user.js @@ -172,23 +172,34 @@ User = ghostBookshelf.Model.extend({ }, - permissable: function (userModelOrId, context) { + permissable: function (userModelOrId, context, loadedPermissions, hasUserPermission, hasAppPermission) { var self = this, - userId = context.user, - userModel = userModelOrId; + userModel = userModelOrId, + origArgs; // If we passed in an id instead of a model, get the model // then check the permissions if (_.isNumber(userModelOrId) || _.isString(userModelOrId)) { + // Grab the original args without the first one + origArgs = _.toArray(arguments).slice(1); + // Get the actual post model return this.findOne({id: userModelOrId}).then(function (foundUserModel) { - return self.permissable(foundUserModel, context); + // Build up the original args but substitute with actual model + var newArgs = [foundUserModel].concat(origArgs); + + return self.permissable.apply(self, newArgs); }, errors.logAndThrowError); } - // If this is the same user that requests the operation allow it. - if (userModel && userId === userModel.get('id')) { + if (userModel) { + // If this is the same user that requests the operation allow it. + hasUserPermission = hasUserPermission || context.user === userModel.get('id'); + } + + if (hasUserPermission && hasAppPermission) { return when.resolve(); } + return when.reject(); }, diff --git a/core/server/permissions/index.js b/core/server/permissions/index.js index f450696b40..5d4dccf545 100644 --- a/core/server/permissions/index.js +++ b/core/server/permissions/index.js @@ -120,16 +120,14 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type, hasAppPermission = _.any(appPermissions, checkPermission); } + // Offer a chance for the TargetModel to override the results + if (TargetModel && _.isFunction(TargetModel.permissable)) { + return TargetModel.permissable(modelId, context, loadedPermissions, hasUserPermission, hasAppPermission); + } + if (hasUserPermission && hasAppPermission) { return when.resolve(); } - return when.reject(); - }).otherwise(function () { - // Check for special permissions on the model directly - if (TargetModel && _.isFunction(TargetModel.permissable)) { - return TargetModel.permissable(modelId, context); - } - return when.reject(); }); };