Skip to content

Commit

Permalink
Added /roles/ API endpoint
Browse files Browse the repository at this point in the history
Closes #3196

* adds `/roles/` endpoint
* is given the current user as context
* wraps everything in a canthis.browse.role
* gets all the available roles (should "Owner" be filtered out?)
* optional parameter: `permission=assign`. Gets all roles authenticated user could assign
* if we're not signed in, gives a "please sign in" (standard) error
* if we're signed in, but user is not in the context, gives a "there was no user in the context" error
* if the user is an "Author", gives a "there are no available roles to assign" error
* implemented hacky filter because when.js produces heisenbugs past 3.2.3 (when.filter not available)
* added extra fixtures to `permissions.json`. Might need a migration.

Caveats:

* there are no tests
* for some reason the setup functional test was failing for me locally
  • Loading branch information
javorszky committed Jul 21, 2014
1 parent 4c27660 commit 80f9023
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 5 deletions.
2 changes: 2 additions & 0 deletions core/server/api/index.js
Expand Up @@ -12,6 +12,7 @@ var _ = require('lodash'),
mail = require('./mail'),
notifications = require('./notifications'),
posts = require('./posts'),
roles = require('./roles'),
settings = require('./settings'),
tags = require('./tags'),
themes = require('./themes'),
Expand Down Expand Up @@ -280,6 +281,7 @@ module.exports = {
mail: mail,
notifications: notifications,
posts: posts,
roles: roles,
settings: settings,
tags: tags,
themes: themes,
Expand Down
60 changes: 60 additions & 0 deletions core/server/api/roles.js
@@ -0,0 +1,60 @@
// # Posts API
// RESTful API for the Post resource
var when = require('when'),
_ = require('lodash'),
canThis = require('../permissions').canThis,
dataProvider = require('../models'),
errors = require('../errors'),

roles;

/**
* ## Roles API Methods
*
* **See:** [API Methods](index.js.html#api%20methods)
*/
roles = {
/**
* ### Browse
* Find all roles
*
* Will return all roles that the current user is able to assign
*
*
* @public
* @param {{context, page, limit, status, staticPages, tag}} options (optional)
* @returns {Promise(Roles)} Roles Collection
*/
browse: function browse(options) {
var permissionMap = [];
options = options || {};

return canThis(options.context).browse.role().then(function () {
return dataProvider.Role.findAll(options).then(function (foundRoles) {
if (options.permissions === 'assign') {
// Hacky implementation of filtering because when.filter is only available in when 3.4.0,
// but that's buggy and kills other tests and introduces Heisenbugs. Until we turn everything
// to Bluebird, this works. Sorry.
// TODO: replace with better filter when bluebird lands
_.each(foundRoles.toJSON(), function (role) {
permissionMap.push(canThis(options.context).assign.role(role).then(function () {
return role;
}, function () {
return null;
}));
});

return when.all(permissionMap).then(function (resolved) {
return { roles: _.filter(resolved, function (role) {
return role !== null;
}) };
}).catch(errors.logAndThrowError);
}
return { roles: foundRoles.toJSON() };
});
})
.catch(errors.logAndThrowError);
}
};

module.exports = roles;
22 changes: 18 additions & 4 deletions core/server/data/fixtures/permissions/permissions.json
Expand Up @@ -129,6 +129,16 @@
"name": "Delete users",
"action_type": "destroy"
}
],
"role": [
{
"name": "Assign a role",
"action_type": "assign"
},
{
"name": "Browse roles",
"action_type": "browse"
}
]
},
"permissions_roles": {
Expand All @@ -141,22 +151,26 @@
"slug": "all",
"tag": "all",
"theme": "all",
"user": "all"
"user": "all",
"role": "all"
},
"Editor": {
"post": "all",
"setting": ["browse", "read"],
"slug": "all",
"tag": "all",
"user": "all"

"user": "all",
"setting": ["browse", "read"],
"role": "all"
},
"Author": {
"post": ["browse", "read", "add"],
"setting": ["browse", "read"],
"slug": "all",
"tag": ["browse", "read", "add"],
"user": ["browse", "read"]
"user": ["browse", "read"],
"setting": ["browse", "read"],
"role": ["browse"]
}
}
}
46 changes: 45 additions & 1 deletion core/server/models/role.js
@@ -1,4 +1,7 @@
var ghostBookshelf = require('./base'),
var _ = require('lodash'),
errors = require('../errors'),
ghostBookshelf = require('./base'),
when = require('when'),

Role,
Roles;
Expand Down Expand Up @@ -34,6 +37,47 @@ Role = ghostBookshelf.Model.extend({
}

return options;
},


permissable: function (roleModelOrId, context, loadedPermissions, hasUserPermission, hasAppPermission) {
var self = this,
checkAgainst = [],
origArgs;

// If we passed in an id instead of a model, get the model
// then check the permissions
if (_.isNumber(roleModelOrId) || _.isString(roleModelOrId)) {
// Grab the original args without the first one
origArgs = _.toArray(arguments).slice(1);
// Get the actual post model
return this.findOne({id: roleModelOrId, status: 'all'}).then(function (foundRoleModel) {
// Build up the original args but substitute with actual model
var newArgs = [foundRoleModel].concat(origArgs);

return self.permissable.apply(self, newArgs);
}, errors.logAndThrowError);
}

switch (loadedPermissions.user) {
case 'Owner':
case 'Administrator':
checkAgainst = ['Administrator', 'Editor', 'Author'];
break;
case 'Editor':
checkAgainst = ['Editor', 'Author'];
}

// If we have a role passed into here
if (roleModelOrId && !_.contains(checkAgainst, roleModelOrId.get('name'))) {
// Role not in the list of permissible roles
hasUserPermission = false;
}

if (hasUserPermission && hasAppPermission) {
return when.resolve();
}
return when.reject();
}
});

Expand Down
3 changes: 3 additions & 0 deletions core/server/routes/api.js
Expand Up @@ -34,6 +34,9 @@ apiRoutes = function (middleware) {
// ## Tags
router.get('/tags', api.http(api.tags.browse));

// ## Roles
router.get('/roles/', api.http(api.roles.browse));

// ## Slugs
router.get('/slugs/:type/:name', api.http(api.slugs.generate));

Expand Down

0 comments on commit 80f9023

Please sign in to comment.