Permissions / ACL
- Created Role model - Created Permission model - Linked Users->Roles with a belongsToMany relationship - Linked Permissions to Users and Roles with a belongsToMany relationship - Created permissions helper with functions for initializing and checking permissions (canThis) - Unit tests for lots of things
This commit is contained in:
parent
d047692c73
commit
e6f7c706cb
@ -63,5 +63,71 @@ module.exports = {
|
||||
"created_by": 1,
|
||||
"updated_by": 1
|
||||
}
|
||||
],
|
||||
|
||||
roles: [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Administrator",
|
||||
"description": "Administrators"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Editor",
|
||||
"description": "Editors"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Author",
|
||||
"description": "Authors"
|
||||
}
|
||||
],
|
||||
|
||||
roles_users: [
|
||||
{
|
||||
"id": 1,
|
||||
"role_id": 1,
|
||||
"user_id": 1
|
||||
}
|
||||
],
|
||||
|
||||
permissions: [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Edit posts",
|
||||
"action_type": "edit",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Remove posts",
|
||||
"action_type": "remove",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Create posts",
|
||||
"action_type": "create",
|
||||
"object_type": "post"
|
||||
}
|
||||
],
|
||||
|
||||
permissions_roles: [
|
||||
{
|
||||
"id": 1,
|
||||
"permission_id": 1,
|
||||
"role_id": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"permission_id": 2,
|
||||
"role_id": 1
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"permission_id": 3,
|
||||
"role_id": 1
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
|
@ -47,6 +47,38 @@
|
||||
t.integer('updated_by');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('roles', function (t) {
|
||||
t.increments().primary();
|
||||
t.string('name');
|
||||
t.string('description');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('roles_users', function (t) {
|
||||
t.increments().primary();
|
||||
t.integer('role_id');
|
||||
t.integer('user_id');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('permissions', function (t) {
|
||||
t.increments().primary();
|
||||
t.string('name');
|
||||
t.string('object_type');
|
||||
t.string('action_type');
|
||||
t.integer('object_id');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('permissions_users', function (t) {
|
||||
t.increments().primary();
|
||||
t.integer('user_id');
|
||||
t.integer('permission_id');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('permissions_roles', function(t) {
|
||||
t.increments().primary();
|
||||
t.integer('role_id');
|
||||
t.integer('permission_id');
|
||||
}),
|
||||
|
||||
knex.Schema.createTable('settings', function (t) {
|
||||
t.increments().primary();
|
||||
t.string('key');
|
||||
@ -63,6 +95,10 @@
|
||||
return when.all([
|
||||
knex('posts').insert(fixtures.posts),
|
||||
knex('users').insert(fixtures.users),
|
||||
knex('roles').insert(fixtures.roles),
|
||||
knex('roles_users').insert(fixtures.roles_users),
|
||||
knex('permissions').insert(fixtures.permissions),
|
||||
knex('permissions_roles').insert(fixtures.permissions_roles),
|
||||
knex('settings').insert(fixtures.settings)
|
||||
]);
|
||||
|
||||
@ -74,8 +110,17 @@
|
||||
return when.all([
|
||||
knex.Schema.dropTableIfExists("posts"),
|
||||
knex.Schema.dropTableIfExists("users"),
|
||||
knex.Schema.dropTableIfExists("settings")
|
||||
]);
|
||||
knex.Schema.dropTableIfExists("roles"),
|
||||
knex.Schema.dropTableIfExists("settings"),
|
||||
knex.Schema.dropTableIfExists("permissions")
|
||||
]).then(function() {
|
||||
// Drop the relation tables after the model tables?
|
||||
return when.all([
|
||||
knex.Schema.dropTableIfExists("roles_users"),
|
||||
knex.Schema.dropTableIfExists("permissions_users"),
|
||||
knex.Schema.dropTableIfExists("permissions_roles")
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
exports.up = up;
|
||||
|
@ -21,6 +21,7 @@
|
||||
},
|
||||
|
||||
logError: function (err) {
|
||||
err = err || "Unknown";
|
||||
// TODO: Logging framework hookup
|
||||
console.log("Error occurred: ", err.message || err);
|
||||
},
|
||||
|
@ -9,6 +9,8 @@
|
||||
module.exports = {
|
||||
Post: require('./post').Post,
|
||||
User: require('./user').User,
|
||||
Role: require('./role').Role,
|
||||
Permission: require('./permission').Permission,
|
||||
Setting: require('./setting').Setting,
|
||||
init: function () {
|
||||
return knex.Schema.hasTable('posts').then(null, function () {
|
||||
|
31
core/shared/models/permission.js
Normal file
31
core/shared/models/permission.js
Normal file
@ -0,0 +1,31 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var GhostBookshelf = require('./base'),
|
||||
User = require('./user').User,
|
||||
Role = require('./role').Role,
|
||||
Permission,
|
||||
Permissions;
|
||||
|
||||
Permission = GhostBookshelf.Model.extend({
|
||||
tableName: 'permissions',
|
||||
|
||||
roles: function () {
|
||||
return this.belongsToMany(Role);
|
||||
},
|
||||
|
||||
users: function () {
|
||||
return this.belongsToMany(User);
|
||||
}
|
||||
});
|
||||
|
||||
Permissions = GhostBookshelf.Collection.extend({
|
||||
model: Permission
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
Permission: Permission,
|
||||
Permissions: Permissions
|
||||
};
|
||||
|
||||
}());
|
32
core/shared/models/role.js
Normal file
32
core/shared/models/role.js
Normal file
@ -0,0 +1,32 @@
|
||||
(function () {
|
||||
|
||||
"use strict";
|
||||
|
||||
var User = require('./user').User,
|
||||
Permission = require('./permission').Permission,
|
||||
GhostBookshelf = require('./base'),
|
||||
Role,
|
||||
Roles;
|
||||
|
||||
Role = GhostBookshelf.Model.extend({
|
||||
tableName: 'roles',
|
||||
|
||||
users: function () {
|
||||
return this.belongsToMany(User);
|
||||
},
|
||||
|
||||
permissions: function () {
|
||||
return this.belongsToMany(Permission);
|
||||
}
|
||||
});
|
||||
|
||||
Roles = GhostBookshelf.Collection.extend({
|
||||
model: Role
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
Role: Role,
|
||||
Roles: Roles
|
||||
};
|
||||
|
||||
}());
|
@ -8,7 +8,9 @@
|
||||
nodefn = require('when/node/function'),
|
||||
bcrypt = require('bcrypt-nodejs'),
|
||||
Posts = require('./post').Posts,
|
||||
GhostBookshelf = require('./base');
|
||||
GhostBookshelf = require('./base'),
|
||||
Role = require('./role').Role,
|
||||
Permission = require('./permission').Permission;
|
||||
|
||||
User = GhostBookshelf.Model.extend({
|
||||
|
||||
@ -18,6 +20,14 @@
|
||||
|
||||
posts: function () {
|
||||
return this.hasMany(Posts, 'created_by');
|
||||
},
|
||||
|
||||
roles: function () {
|
||||
return this.belongsToMany(Role);
|
||||
},
|
||||
|
||||
permissions: function () {
|
||||
return this.belongsToMany(Permission);
|
||||
}
|
||||
|
||||
}, {
|
||||
@ -62,6 +72,35 @@
|
||||
return user;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
effectivePermissions: function (id) {
|
||||
return this.read({id: id}, { withRelated: ['permissions', 'roles.permissions'] })
|
||||
.then(function (foundUser) {
|
||||
var seenPerms = {},
|
||||
rolePerms = _.map(foundUser.related('roles').models, function (role) {
|
||||
return role.related('permissions').models;
|
||||
}),
|
||||
allPerms = [];
|
||||
|
||||
rolePerms.push(foundUser.related('permissions').models);
|
||||
|
||||
_.each(rolePerms, function (rolePermGroup) {
|
||||
_.each(rolePermGroup, function (perm) {
|
||||
var key = perm.get('action_type') + '-' + perm.get('object_type') + '-' + perm.get('object_id');
|
||||
|
||||
// Only add perms once
|
||||
if (seenPerms[key]) {
|
||||
return;
|
||||
}
|
||||
|
||||
allPerms.push(perm);
|
||||
seenPerms[key] = true;
|
||||
});
|
||||
});
|
||||
|
||||
return when.resolve(allPerms);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
160
core/shared/permissions/index.js
Normal file
160
core/shared/permissions/index.js
Normal file
@ -0,0 +1,160 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// canThis(someUser).edit.posts([id]|[[ids]])
|
||||
// canThis(someUser).edit.post(somePost|somePostId)
|
||||
|
||||
var _ = require('underscore'),
|
||||
when = require('when'),
|
||||
Models = require('../models'),
|
||||
UserProvider = Models.User,
|
||||
PermissionsProvider = Models.Permission,
|
||||
init,
|
||||
refresh,
|
||||
canThis,
|
||||
CanThisResult,
|
||||
exported;
|
||||
|
||||
// Base class for canThis call results
|
||||
CanThisResult = function () {
|
||||
this.userPermissionLoad = false;
|
||||
};
|
||||
|
||||
CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type) {
|
||||
var self = this,
|
||||
obj_type_handlers = {};
|
||||
|
||||
// Iterate through the object types, i.e. ['post', 'tag', 'user']
|
||||
_.each(obj_types, function (obj_type) {
|
||||
|
||||
// Create the 'handler' for the object type;
|
||||
// the '.post()' in canThis(user).edit.post()
|
||||
obj_type_handlers[obj_type] = function (modelOrId) {
|
||||
var modelId;
|
||||
|
||||
if (_.isNumber(modelOrId) || _.isString(modelOrId)) {
|
||||
// It's an id already, do nothing
|
||||
modelId = modelOrId;
|
||||
} else if (modelOrId) {
|
||||
// It's a model, get the id
|
||||
modelId = modelOrId.id;
|
||||
}
|
||||
|
||||
// Wait for the user loading to finish
|
||||
return self.userPermissionLoad.then(function (userPermissions) {
|
||||
|
||||
// Iterate through the user permissions looking for an affirmation
|
||||
var hasPermission = _.any(userPermissions, function (userPermission) {
|
||||
var permObjId;
|
||||
|
||||
// Look for a matching action type and object type first
|
||||
if (userPermission.get('action_type') !== act_type || userPermission.get('object_type') !== obj_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grab the object id (if specified, could be null)
|
||||
permObjId = userPermission.get('object_id');
|
||||
|
||||
// If we didn't specify a model (any thing)
|
||||
// or the permission didn't have an id scope set
|
||||
// then the user has permission
|
||||
if (!modelId || !permObjId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, check if the id's match
|
||||
// TODO: String vs Int comparison possibility here?
|
||||
return modelId === permObjId;
|
||||
});
|
||||
|
||||
if (hasPermission) {
|
||||
return when.resolve();
|
||||
}
|
||||
|
||||
return when.reject();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
return obj_type_handlers;
|
||||
};
|
||||
|
||||
CanThisResult.prototype.beginCheck = function (user) {
|
||||
var self = this;
|
||||
|
||||
// TODO: Switch logic based on object type; user, role, post.
|
||||
|
||||
// Kick off the fetching of the user data
|
||||
this.userPermissionLoad = UserProvider.effectivePermissions(user.id || user);
|
||||
|
||||
// Iterate through the actions and their related object types
|
||||
// We should have loaded these through a permissions.init() call previously
|
||||
// TODO: Throw error if not init() yet?
|
||||
_.each(exported.actionsMap, function (obj_types, act_type) {
|
||||
// Build up the object type handlers;
|
||||
// the '.post()' parts in canThis(user).edit.post()
|
||||
var obj_type_handlers = self.buildObjectTypeHandlers(obj_types, act_type);
|
||||
|
||||
// Define a property for the action on the result;
|
||||
// the '.edit' in canThis(user).edit.post()
|
||||
Object.defineProperty(self, act_type, {
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
value: obj_type_handlers
|
||||
});
|
||||
});
|
||||
|
||||
// Return this for chaining
|
||||
return this;
|
||||
};
|
||||
|
||||
canThis = function (user) {
|
||||
var result = new CanThisResult();
|
||||
|
||||
return result.beginCheck(user);
|
||||
};
|
||||
|
||||
init = refresh = function () {
|
||||
// Load all the permissions
|
||||
return PermissionsProvider.browse().then(function (perms) {
|
||||
var seenActions = {};
|
||||
|
||||
exported.actionsMap = {};
|
||||
|
||||
// Build a hash map of the actions on objects, i.e
|
||||
/*
|
||||
{
|
||||
'edit': ['post', 'tag', 'user', 'page'],
|
||||
'delete': ['post', 'user'],
|
||||
'create': ['post', 'user', 'page']
|
||||
}
|
||||
*/
|
||||
_.each(perms.models, function (perm) {
|
||||
var action_type = perm.get('action_type'),
|
||||
object_type = perm.get('object_type');
|
||||
|
||||
exported.actionsMap[action_type] = exported.actionsMap[action_type] || [];
|
||||
seenActions[action_type] = seenActions[action_type] || {};
|
||||
|
||||
// Check if we've already seen this action -> object combo
|
||||
if (seenActions[action_type][object_type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
exported.actionsMap[action_type].push(object_type);
|
||||
seenActions[action_type][object_type] = true;
|
||||
});
|
||||
|
||||
return when(exported.actionsMap);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = exported = {
|
||||
init: init,
|
||||
refresh: refresh,
|
||||
canThis: canThis,
|
||||
actionsMap: {}
|
||||
};
|
||||
|
||||
}());
|
171
core/test/ghost/api_permissions_spec.js
Normal file
171
core/test/ghost/api_permissions_spec.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*globals describe, beforeEach, it*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var should = require('should'),
|
||||
helpers = require('./helpers'),
|
||||
errors = require('../../shared/errorHandling'),
|
||||
Models = require('../../shared/models');
|
||||
|
||||
describe("Role Model", function () {
|
||||
|
||||
var RoleModel = Models.Role;
|
||||
|
||||
should.exist(RoleModel);
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.resetData().then(function() {
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
it("can browse roles", function (done) {
|
||||
RoleModel.browse().then(function (foundRoles) {
|
||||
should.exist(foundRoles);
|
||||
|
||||
foundRoles.models.length.should.be.above(0);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can read roles", function (done) {
|
||||
RoleModel.read({id: 1}).then(function (foundRole) {
|
||||
should.exist(foundRole);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can edit roles", function (done) {
|
||||
RoleModel.read({id: 1}).then(function (foundRole) {
|
||||
should.exist(foundRole);
|
||||
|
||||
return foundRole.set({name: "updated"}).save();
|
||||
}).then(function () {
|
||||
return RoleModel.read({id: 1});
|
||||
}).then(function (updatedRole) {
|
||||
should.exist(updatedRole);
|
||||
|
||||
updatedRole.get("name").should.equal("updated");
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can add roles", function (done) {
|
||||
var newRole = {
|
||||
name: "test1",
|
||||
description: "test1 description"
|
||||
};
|
||||
|
||||
RoleModel.add(newRole).then(function (createdRole) {
|
||||
should.exist(createdRole);
|
||||
|
||||
createdRole.attributes.name.should.equal(newRole.name);
|
||||
createdRole.attributes.description.should.equal(newRole.description);
|
||||
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
it("can delete roles", function (done) {
|
||||
RoleModel.read({id: 1}).then(function (foundRole) {
|
||||
should.exist(foundRole);
|
||||
|
||||
return RoleModel['delete'](1);
|
||||
}).then(function () {
|
||||
return RoleModel.browse();
|
||||
}).then(function (foundRoles) {
|
||||
var hasRemovedId = foundRoles.any(function(role) {
|
||||
return role.id === 1;
|
||||
});
|
||||
|
||||
hasRemovedId.should.equal(false);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Permission Model", function () {
|
||||
|
||||
var PermissionModel = Models.Permission;
|
||||
|
||||
should.exist(PermissionModel);
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.resetData().then(function() {
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
it("can browse permissions", function (done) {
|
||||
PermissionModel.browse().then(function (foundPermissions) {
|
||||
should.exist(foundPermissions);
|
||||
|
||||
foundPermissions.models.length.should.be.above(0);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can read permissions", function (done) {
|
||||
PermissionModel.read({id: 1}).then(function (foundPermission) {
|
||||
should.exist(foundPermission);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can edit permissions", function (done) {
|
||||
PermissionModel.read({id: 1}).then(function (foundPermission) {
|
||||
should.exist(foundPermission);
|
||||
|
||||
return foundPermission.set({name: "updated"}).save();
|
||||
}).then(function () {
|
||||
return PermissionModel.read({id: 1});
|
||||
}).then(function (updatedPermission) {
|
||||
should.exist(updatedPermission);
|
||||
|
||||
updatedPermission.get("name").should.equal("updated");
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
|
||||
it("can add permissions", function (done) {
|
||||
var newPerm = {
|
||||
name: "testperm1"
|
||||
};
|
||||
|
||||
PermissionModel.add(newPerm).then(function (createdPerm) {
|
||||
should.exist(createdPerm);
|
||||
|
||||
createdPerm.attributes.name.should.equal(newPerm.name);
|
||||
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
||||
it("can delete permissions", function (done) {
|
||||
PermissionModel.read({id: 1}).then(function (foundPermission) {
|
||||
should.exist(foundPermission);
|
||||
|
||||
return PermissionModel['delete'](1);
|
||||
}).then(function () {
|
||||
return PermissionModel.browse();
|
||||
}).then(function (foundPermissions) {
|
||||
var hasRemovedId = foundPermissions.any(function(permission) {
|
||||
return permission.id === 1;
|
||||
});
|
||||
|
||||
hasRemovedId.should.equal(false);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
});
|
||||
|
||||
}());
|
@ -8,7 +8,7 @@
|
||||
helpers = require('./helpers'),
|
||||
Models = require('../../shared/models');
|
||||
|
||||
describe('Bookshelf Post Model', function () {
|
||||
describe('Post Model', function () {
|
||||
|
||||
var PostModel = Models.Post;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
helpers = require('./helpers'),
|
||||
Models = require('../../shared/models');
|
||||
|
||||
describe('Bookshelf Setting Model', function () {
|
||||
describe('Setting Model', function () {
|
||||
|
||||
var SettingModel = Models.Setting;
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
var _ = require('underscore'),
|
||||
should = require('should'),
|
||||
helpers = require('./helpers'),
|
||||
errors = require('../../shared/errorHandling'),
|
||||
Models = require('../../shared/models');
|
||||
|
||||
describe('Bookshelf User Model', function () {
|
||||
describe('User Model', function () {
|
||||
|
||||
var UserModel = Models.User;
|
||||
|
||||
@ -134,6 +135,16 @@
|
||||
|
||||
}).then(null, done);
|
||||
});
|
||||
|
||||
it("can get effective permissions", function (done) {
|
||||
UserModel.effectivePermissions(1).then(function (effectivePermissions) {
|
||||
should.exist(effectivePermissions);
|
||||
|
||||
effectivePermissions.length.should.be.above(0);
|
||||
|
||||
done();
|
||||
}, errors.logError);
|
||||
});
|
||||
});
|
||||
|
||||
}());
|
@ -11,10 +11,12 @@
|
||||
describe("Ghost API", function () {
|
||||
|
||||
it("is a singleton", function () {
|
||||
var ghost1 = new Ghost(),
|
||||
var logStub = sinon.stub(console, "log"),
|
||||
ghost1 = new Ghost(),
|
||||
ghost2 = new Ghost();
|
||||
|
||||
should.strictEqual(ghost1, ghost2);
|
||||
logStub.restore();
|
||||
});
|
||||
|
||||
it("uses init() to initialize", function (done) {
|
||||
|
226
core/test/ghost/permissions_spec.js
Normal file
226
core/test/ghost/permissions_spec.js
Normal file
@ -0,0 +1,226 @@
|
||||
/*globals describe, beforeEach, it*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var _ = require("underscore"),
|
||||
when = require('when'),
|
||||
should = require('should'),
|
||||
errors = require('../../shared/errorHandling'),
|
||||
helpers = require('./helpers'),
|
||||
permissions = require('../../shared/permissions'),
|
||||
Models = require('../../shared/models'),
|
||||
UserProvider = Models.User,
|
||||
PermissionsProvider = Models.Permission;
|
||||
|
||||
describe('permissions', function () {
|
||||
|
||||
should.exist(permissions);
|
||||
|
||||
beforeEach(function (done) {
|
||||
helpers.resetData().then(function () { done(); }, errors.throwError);
|
||||
});
|
||||
|
||||
var testPerms = [
|
||||
{ act: "edit", obj: "post" },
|
||||
{ act: "edit", obj: "tag" },
|
||||
{ act: "edit", obj: "user" },
|
||||
{ act: "edit", obj: "page" },
|
||||
{ act: "add", obj: "post" },
|
||||
{ act: "add", obj: "user" },
|
||||
{ act: "add", obj: "page" },
|
||||
{ act: "remove", obj: "post" },
|
||||
{ act: "remove", obj: "user" }
|
||||
],
|
||||
currTestPermId = 1,
|
||||
createPermission = function (name, act, obj) {
|
||||
if (!name) {
|
||||
currTestPermId += 1;
|
||||
name = "test" + currTestPermId;
|
||||
}
|
||||
|
||||
var newPerm = {
|
||||
name: name,
|
||||
action_type: act,
|
||||
object_type: obj
|
||||
};
|
||||
|
||||
return PermissionsProvider.add(newPerm);
|
||||
},
|
||||
createTestPermissions = function() {
|
||||
var createActions = _.map(testPerms, function (testPerm) {
|
||||
return createPermission(null, testPerm.act, testPerm.obj);
|
||||
});
|
||||
|
||||
return when.all(createActions);
|
||||
};
|
||||
|
||||
it('can load an actions map from existing permissions', function (done) {
|
||||
|
||||
createTestPermissions()
|
||||
.then(permissions.init)
|
||||
.then(function (actionsMap) {
|
||||
should.exist(actionsMap);
|
||||
|
||||
actionsMap.edit.should.eql(['post', 'tag', 'user', 'page']);
|
||||
|
||||
actionsMap.should.equal(permissions.actionsMap);
|
||||
|
||||
done();
|
||||
}, errors.throwError);
|
||||
});
|
||||
|
||||
it('can add user to role', function (done) {
|
||||
var existingUserRoles;
|
||||
|
||||
UserProvider.read({id: 1}, { withRelated: ['roles'] }).then(function (foundUser) {
|
||||
var testRole = new Models.Role({
|
||||
name: 'testrole1',
|
||||
description: 'testrole1 description'
|
||||
});
|
||||
|
||||
should.exist(foundUser);
|
||||
|
||||
should.exist(foundUser.roles());
|
||||
|
||||
existingUserRoles = foundUser.related('roles').length;
|
||||
|
||||
return testRole.save().then(function () {
|
||||
return foundUser.roles().attach(testRole);
|
||||
});
|
||||
}).then(function () {
|
||||
return UserProvider.read({id: 1}, { withRelated: ['roles'] });
|
||||
}).then(function (updatedUser) {
|
||||
should.exist(updatedUser);
|
||||
|
||||
updatedUser.related('roles').length.should.equal(existingUserRoles + 1);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can add user permissions', function (done) {
|
||||
Models.User.read({id: 1}, { withRelated: ['permissions']}).then(function (testUser) {
|
||||
var testPermission = new Models.Permission({
|
||||
name: "test edit posts",
|
||||
action_type: 'edit',
|
||||
object_type: 'post'
|
||||
});
|
||||
|
||||
testUser.related('permissions').length.should.equal(0);
|
||||
|
||||
return testPermission.save().then(function () {
|
||||
return testUser.permissions().attach(testPermission);
|
||||
});
|
||||
}).then(function () {
|
||||
return Models.User.read({id: 1}, { withRelated: ['permissions']});
|
||||
}).then(function (updatedUser) {
|
||||
should.exist(updatedUser);
|
||||
|
||||
updatedUser.related('permissions').length.should.equal(1);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can add role permissions', function (done) {
|
||||
var testRole = new Models.Role({
|
||||
name: "test2",
|
||||
description: "test2 description"
|
||||
});
|
||||
|
||||
testRole.save().then(function () {
|
||||
return testRole.load('permissions');
|
||||
}).then(function () {
|
||||
var rolePermission = new Models.Permission({
|
||||
name: "test edit posts",
|
||||
action_type: 'edit',
|
||||
object_type: 'post'
|
||||
});
|
||||
|
||||
testRole.related('permissions').length.should.equal(0);
|
||||
|
||||
return rolePermission.save().then(function () {
|
||||
return testRole.permissions().attach(rolePermission);
|
||||
});
|
||||
}).then(function () {
|
||||
return Models.Role.read({id: testRole.id}, { withRelated: ['permissions']});
|
||||
}).then(function (updatedRole) {
|
||||
should.exist(updatedRole);
|
||||
|
||||
updatedRole.related('permissions').length.should.equal(1);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not allow edit post without permission', function (done) {
|
||||
var fakePage = {
|
||||
id: 1
|
||||
};
|
||||
|
||||
createTestPermissions()
|
||||
.then(permissions.init)
|
||||
.then(function () {
|
||||
return Models.User.read({id: 1});
|
||||
})
|
||||
.then(function (foundUser) {
|
||||
var canThisResult = permissions.canThis(foundUser);
|
||||
|
||||
should.exist(canThisResult.edit);
|
||||
should.exist(canThisResult.edit.post);
|
||||
|
||||
return canThisResult.edit.page(fakePage);
|
||||
})
|
||||
.then(function () {
|
||||
errors.logError(new Error("Allowed edit post without permission"));
|
||||
}, function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows edit post with permission', function (done) {
|
||||
var fakePost = {
|
||||
id: "1"
|
||||
};
|
||||
|
||||
createTestPermissions()
|
||||
.then(permissions.init)
|
||||
.then(function () {
|
||||
return Models.User.read({id: 1});
|
||||
})
|
||||
.then(function (foundUser) {
|
||||
var newPerm = new Models.Permission({
|
||||
name: "test3 edit post",
|
||||
action_type: "edit",
|
||||
object_type: "post"
|
||||
});
|
||||
|
||||
return newPerm.save().then(function () {
|
||||
return foundUser.permissions().attach(newPerm);
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return Models.User.read({id: 1}, { withRelated: ['permissions']});
|
||||
})
|
||||
.then(function (updatedUser) {
|
||||
|
||||
// TODO: Verify updatedUser.related('permissions') has the permission?
|
||||
|
||||
var canThisResult = permissions.canThis(updatedUser);
|
||||
|
||||
should.exist(canThisResult.edit);
|
||||
should.exist(canThisResult.edit.post);
|
||||
|
||||
return canThisResult.edit.post(fakePost);
|
||||
})
|
||||
.then(function () {
|
||||
done();
|
||||
}, function () {
|
||||
errors.logError(new Error("Did not allow edit post with permission"));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}());
|
Loading…
Reference in New Issue
Block a user