Merge pull request #3146 from strongloop/feature/promisify-role
Promise-ify built-in Role model
This commit is contained in:
commit
5fd79b14f4
|
@ -8,6 +8,7 @@ var loopback = require('../../lib/loopback');
|
|||
var debug = require('debug')('loopback:security:role');
|
||||
var assert = require('assert');
|
||||
var async = require('async');
|
||||
var utils = require('../../lib/utils');
|
||||
|
||||
var AccessContext = require('../../lib/access-context').AccessContext;
|
||||
|
||||
|
@ -37,21 +38,40 @@ module.exports = function(Role) {
|
|||
* Fetch all users assigned to this role
|
||||
* @function Role.prototype#users
|
||||
* @param {object} [query] query object passed to model find call
|
||||
* @param {Function} [callback]
|
||||
* @callback {Function} [callback] The callback function
|
||||
* @param {String|Error} err The error string or object
|
||||
* @param {Array} list The list of users.
|
||||
* @promise
|
||||
*/
|
||||
/**
|
||||
* Fetch all applications assigned to this role
|
||||
* @function Role.prototype#applications
|
||||
* @param {object} [query] query object passed to model find call
|
||||
* @param {Function} [callback]
|
||||
* @callback {Function} [callback] The callback function
|
||||
* @param {String|Error} err The error string or object
|
||||
* @param {Array} list The list of applications.
|
||||
* @promise
|
||||
*/
|
||||
/**
|
||||
* Fetch all roles assigned to this role
|
||||
* @function Role.prototype#roles
|
||||
* @param {object} [query] query object passed to model find call
|
||||
* @param {Function} [callback]
|
||||
* @callback {Function} [callback] The callback function
|
||||
* @param {String|Error} err The error string or object
|
||||
* @param {Array} list The list of roles.
|
||||
* @promise
|
||||
*/
|
||||
Role.prototype[rel] = function(query, callback) {
|
||||
if (!callback) {
|
||||
if (typeof query === 'function') {
|
||||
callback = query;
|
||||
query = {};
|
||||
} else {
|
||||
callback = utils.createPromiseCallback();
|
||||
}
|
||||
}
|
||||
if (!query) query = {};
|
||||
|
||||
roleModel.resolveRelatedModels();
|
||||
var relsToModels = {
|
||||
users: roleModel.userModel,
|
||||
|
@ -68,6 +88,7 @@ module.exports = function(Role) {
|
|||
|
||||
var model = relsToModels[rel];
|
||||
listByPrincipalType(this, model, relsToTypes[rel], query, callback);
|
||||
return callback.promise;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -166,17 +187,23 @@ module.exports = function(Role) {
|
|||
* @param {Function} modelClass The model class
|
||||
* @param {*} modelId The model ID
|
||||
* @param {*} userId The user ID
|
||||
* @param {Function} callback Callback function
|
||||
* @callback {Function} [callback] The callback function
|
||||
* @param {String|Error} err The error string or object
|
||||
* @param {Boolean} isOwner True if the user is an owner.
|
||||
* @promise
|
||||
*/
|
||||
Role.isOwner = function isOwner(modelClass, modelId, userId, callback) {
|
||||
assert(modelClass, 'Model class is required');
|
||||
if (!callback) callback = utils.createPromiseCallback();
|
||||
|
||||
debug('isOwner(): %s %s userId: %s', modelClass && modelClass.modelName, modelId, userId);
|
||||
|
||||
// No userId is present
|
||||
if (!userId) {
|
||||
process.nextTick(function() {
|
||||
callback(null, false);
|
||||
});
|
||||
return;
|
||||
return callback.promise;
|
||||
}
|
||||
|
||||
// Is the modelClass User or a subclass of User?
|
||||
|
@ -184,7 +211,7 @@ module.exports = function(Role) {
|
|||
process.nextTick(function() {
|
||||
callback(null, matches(modelId, userId));
|
||||
});
|
||||
return;
|
||||
return callback.promise;
|
||||
}
|
||||
|
||||
modelClass.findById(modelId, function(err, inst) {
|
||||
|
@ -222,6 +249,7 @@ module.exports = function(Role) {
|
|||
}
|
||||
}
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
||||
|
@ -241,11 +269,14 @@ module.exports = function(Role) {
|
|||
* @callback {Function} callback Callback function.
|
||||
* @param {Error} err Error object.
|
||||
* @param {Boolean} isAuthenticated True if the user is authenticated.
|
||||
* @promise
|
||||
*/
|
||||
Role.isAuthenticated = function isAuthenticated(context, callback) {
|
||||
if (!callback) callback = utils.createPromiseCallback();
|
||||
process.nextTick(function() {
|
||||
if (callback) callback(null, context.isAuthenticated());
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
Role.registerResolver(Role.UNAUTHENTICATED, function(role, context, callback) {
|
||||
|
@ -269,12 +300,23 @@ module.exports = function(Role) {
|
|||
* @callback {Function} callback Callback function.
|
||||
* @param {Error} err Error object.
|
||||
* @param {Boolean} isInRole True if the principal is in the specified role.
|
||||
* @promise
|
||||
*/
|
||||
Role.isInRole = function(role, context, callback) {
|
||||
if (!(context instanceof AccessContext)) {
|
||||
context = new AccessContext(context);
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
callback = utils.createPromiseCallback();
|
||||
// historically, isInRole is returning the Role instance instead of true
|
||||
// we are preserving that behaviour for callback-based invocation,
|
||||
// but fixing it when invoked in Promise mode
|
||||
callback.promise = callback.promise.then(function(isInRole) {
|
||||
return !!isInRole;
|
||||
});
|
||||
}
|
||||
|
||||
this.resolveRelatedModels();
|
||||
|
||||
debug('isInRole(): %s', role);
|
||||
|
@ -291,7 +333,7 @@ module.exports = function(Role) {
|
|||
callback
|
||||
);
|
||||
}
|
||||
return;
|
||||
return callback.promise;
|
||||
}
|
||||
|
||||
if (context.principals.length === 0) {
|
||||
|
@ -299,7 +341,7 @@ module.exports = function(Role) {
|
|||
process.nextTick(function() {
|
||||
if (callback) callback(null, false);
|
||||
});
|
||||
return;
|
||||
return callback.promise;
|
||||
}
|
||||
|
||||
var inRole = context.principals.some(function(p) {
|
||||
|
@ -315,7 +357,7 @@ module.exports = function(Role) {
|
|||
process.nextTick(function() {
|
||||
if (callback) callback(null, true);
|
||||
});
|
||||
return;
|
||||
return callback.promise;
|
||||
}
|
||||
|
||||
var roleMappingModel = this.roleMappingModel;
|
||||
|
@ -358,6 +400,7 @@ module.exports = function(Role) {
|
|||
if (callback) callback(null, inRole);
|
||||
});
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -367,12 +410,19 @@ module.exports = function(Role) {
|
|||
* @callback {Function} callback Callback function.
|
||||
* @param {Error} err Error object.
|
||||
* @param {String[]} roles An array of role IDs
|
||||
* @promise
|
||||
*/
|
||||
Role.getRoles = function(context, options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
if (!callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
} else {
|
||||
callback = utils.createPromiseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
if (!options) options = {};
|
||||
|
||||
if (!(context instanceof AccessContext)) {
|
||||
context = new AccessContext(context);
|
||||
|
@ -452,6 +502,7 @@ module.exports = function(Role) {
|
|||
debug('getRoles() returns: %j %j', err, roles);
|
||||
if (callback) callback(err, roles);
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
Role.validatesUniquenessOf('name', {message: 'already exists'});
|
||||
|
|
|
@ -305,6 +305,56 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('supports isInRole() returning a Promise', function(done) {
|
||||
var userData = {name: 'Raymond', email: 'x@y.com', password: 'foobar'};
|
||||
User.create(userData, function(err, user) {
|
||||
if (err) return done(err);
|
||||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
var principalData = {
|
||||
principalType: RoleMapping.USER,
|
||||
principalId: user.id,
|
||||
};
|
||||
role.principals.create(principalData, function(err, p) {
|
||||
if (err) return done(err);
|
||||
Role.isInRole('userRole', principalData)
|
||||
.then(function(inRole) {
|
||||
expect(inRole).to.be.true();
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('supports getRole() returning a Promise', function(done) {
|
||||
var userData = {name: 'Raymond', email: 'x@y.com', password: 'foobar'};
|
||||
User.create(userData, function(err, user) {
|
||||
if (err) return done(err);
|
||||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
var principalData = {
|
||||
principalType: RoleMapping.USER,
|
||||
principalId: user.id,
|
||||
};
|
||||
role.principals.create(principalData, function(err, p) {
|
||||
if (err) return done(err);
|
||||
Role.getRoles(principalData)
|
||||
.then(function(roles) {
|
||||
expect(roles).to.eql([
|
||||
Role.AUTHENTICATED,
|
||||
Role.EVERYONE,
|
||||
role.id,
|
||||
]);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support owner role resolver', function(done) {
|
||||
Role.registerResolver('returnPromise', function(role, context) {
|
||||
return new Promise(function(resolve) {
|
||||
|
@ -730,6 +780,30 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('supports Promise API', function(done) {
|
||||
var userData = {name: 'Raymond', email: 'x@y.com', password: 'foobar'};
|
||||
User.create(userData, function(err, user) {
|
||||
if (err) return done(err);
|
||||
Role.create({name: 'userRole'}, function(err, role) {
|
||||
if (err) return done(err);
|
||||
var principalData = {
|
||||
principalType: RoleMapping.USER,
|
||||
principalId: user.id,
|
||||
};
|
||||
role.principals.create(principalData, function(err, p) {
|
||||
if (err) return done(err);
|
||||
role.users()
|
||||
.then(function(users) {
|
||||
var userIds = users.map(function(u) { return u.id; });
|
||||
expect(userIds).to.eql([user.id]);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isOwner', function() {
|
||||
|
@ -759,5 +833,19 @@ describe('role model', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('supports Promise API', function(done) {
|
||||
var credentials = {email: 'test@example.com', password: 'pass'};
|
||||
User.create(credentials, function(err, user) {
|
||||
if (err) return done(err);
|
||||
|
||||
Role.isOwner(User, user.id, user.id)
|
||||
.then(function(result) {
|
||||
expect(result, 'isOwner result').to.equal(true);
|
||||
done();
|
||||
})
|
||||
.catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue