diff --git a/common/models/role.js b/common/models/role.js index 42d85539..927f5c90 100644 --- a/common/models/role.js +++ b/common/models/role.js @@ -6,6 +6,10 @@ var async = require('async'); var AccessContext = require('../../lib/access-context').AccessContext; var RoleMapping = loopback.RoleMapping; +var Role = loopback.Role; +var User = loopback.User; +var Application = loopback.Application; + assert(RoleMapping, 'RoleMapping model must be defined before Role model'); /** @@ -31,44 +35,69 @@ module.exports = function(Role) { Role.once('dataSourceAttached', function() { var registry = Role.registry; var roleMappingModel = this.RoleMapping || registry.getModelByType(RoleMapping); - Role.prototype.users = function(callback) { - roleMappingModel.find({where: {roleId: this.id, - principalType: RoleMapping.USER}}, function(err, mappings) { - if (err) { - if (callback) callback(err); - return; - } - return mappings.map(function(m) { - return m.principalId; - }); - }); - }; + var principalTypesToModels = {}; - Role.prototype.applications = function(callback) { - roleMappingModel.find({where: {roleId: this.id, - principalType: RoleMapping.APPLICATION}}, function(err, mappings) { - if (err) { - if (callback) callback(err); - return; - } - return mappings.map(function(m) { - return m.principalId; - }); - }); - }; + principalTypesToModels[RoleMapping.USER] = User; + principalTypesToModels[RoleMapping.APPLICATION] = Application; + principalTypesToModels[RoleMapping.ROLE] = Role; - Role.prototype.roles = function(callback) { - roleMappingModel.find({where: {roleId: this.id, - principalType: RoleMapping.ROLE}}, function(err, mappings) { + Object.keys(principalTypesToModels).forEach(function(principalType) { + var model = principalTypesToModels[principalType]; + var pluralName = model.pluralModelName.toLowerCase(); + /** + * Fetch all users assigned to this role + * @function Role.prototype#users + * @param {object} [query] query object passed to model find call + * @param {Function} [callback] + */ + /** + * Fetch all applications assigned to this role + * @function Role.prototype#applications + * @param {object} [query] query object passed to model find call + * @param {Function} [callback] + */ + /** + * Fetch all roles assigned to this role + * @function Role.prototype#roles + * @param {object} [query] query object passed to model find call + * @param {Function} [callback] + */ + Role.prototype[pluralName] = function(query, callback) { + listByPrincipalType(model, principalType, query, callback); + }; + }); + + /** + * Fetch all models assigned to this role + * @private + * @param {*} model model type to fetch + * @param {String} [principalType] principalType used in the rolemapping for model + * @param {object} [query] query object passed to model find call + * @param {Function} [callback] callback function called with `(err, models)` arguments. + */ + function listByPrincipalType(model, principalType, query, callback) { + if (callback === undefined) { + callback = query; + query = {}; + } + + roleMappingModel.find({ + where: {roleId: this.id, principalType: principalType} + }, function(err, mappings) { + var ids; if (err) { - if (callback) callback(err); - return; + return callback(err); } - return mappings.map(function(m) { + ids = mappings.map(function(m) { return m.principalId; }); + query.where = query.where || {}; + query.where.id = {inq: ids}; + model.find(query, function(err, models) { + callback(err, models); + }); }); - }; + } }); diff --git a/lib/builtin-models.js b/lib/builtin-models.js index dba51267..78bf6399 100644 --- a/lib/builtin-models.js +++ b/lib/builtin-models.js @@ -13,6 +13,10 @@ module.exports = function(registry) { require('../common/models/access-token.json'), require('../common/models/access-token.js')); + registry.User = createModel( + require('../common/models/user.json'), + require('../common/models/user.js')); + registry.RoleMapping = createModel( require('../common/models/role-mapping.json'), require('../common/models/role-mapping.js')); @@ -29,10 +33,6 @@ module.exports = function(registry) { require('../common/models/scope.json'), require('../common/models/scope.js')); - registry.User = createModel( - require('../common/models/user.json'), - require('../common/models/user.js')); - registry.Change = createModel( require('../common/models/change.json'), require('../common/models/change.js')); diff --git a/package.json b/package.json index 6dde8d14..d25d48ce 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "loopback-datasource-juggler": "^2.19.1", "loopback-testing": "^1.1.0", "mocha": "^2.1.0", + "sinon": "^1.13.0", "strong-task-emitter": "^0.0.6", "supertest": "^0.15.0" }, diff --git a/test/role.test.js b/test/role.test.js index dfedc6cc..b1aad27e 100644 --- a/test/role.test.js +++ b/test/role.test.js @@ -1,8 +1,10 @@ var assert = require('assert'); +var sinon = require('sinon'); var loopback = require('../index'); var Role = loopback.Role; var RoleMapping = loopback.RoleMapping; var User = loopback.User; +var Application = loopback.Application; var ACL = loopback.ACL; function checkResult(err, result) { @@ -67,8 +69,7 @@ describe('role model', function() { role.users(function(err, users) { assert(!err); assert.equal(users.length, 1); - assert.equal(users[0].principalType, RoleMapping.USER); - assert.equal(users[0].principalId, user.id); + assert.equal(users[0].id, user.id); }); }); }); @@ -100,8 +101,7 @@ describe('role model', function() { role.users(function(err, users) { assert(!err); assert.equal(users.length, 1); - assert.equal(users[0].principalType, RoleMapping.USER); - assert.equal(users[0].principalId, user.id); + assert.equal(users[0].id, user.id); }); }); }); @@ -208,4 +208,64 @@ describe('role model', function() { }); + describe('listByPrincipalType', function() { + var sandbox; + + beforeEach(function() { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it('should fetch all models assigned to the role', function(done) { + var principalTypesToModels = {}; + var runs = 0; + var mappings; + + principalTypesToModels[RoleMapping.USER] = User; + principalTypesToModels[RoleMapping.APPLICATION] = Application; + principalTypesToModels[RoleMapping.ROLE] = Role; + + mappings = Object.keys(principalTypesToModels); + + mappings.forEach(function(principalType) { + var Model = principalTypesToModels[principalType]; + Model.create({name:'test', email:'x@y.com', password: 'foobar'}, function(err, model) { + Role.create({name:'testRole'}, function(err, role) { + role.principals.create({principalType: principalType, principalId: model.id}, function(err, p) { + var pluralName = Model.pluralModelName.toLowerCase(); + role[pluralName](function(err, models) { + assert(!err); + assert.equal(models.length, 1); + if (++runs === mappings.length) { + done(); + } + }); + }); + }); + }); + }); + }); + + it('should apply query', function(done) { + User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function(err, user) { + Role.create({name: 'userRole'}, function(err, role) { + role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function(err, p) { + var query = {fields:['id', 'name']}; + sandbox.spy(User, 'find'); + role.users(query, function(err, users) { + assert(!err); + assert.equal(users.length, 1); + assert.equal(users[0].id, user.id); + assert(User.find.calledWith(query)); + done(); + }); + }); + }); + }); + }); + }); + });