Created
October 20, 2015 14:27
-
-
Save psi-4ward/2eee9b0d67302932bb77 to your computer and use it in GitHub Desktop.
Loopback User model with *roles* property support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Loopback User model with *roles* property support | |
*/ | |
var builtinUser = require('loopback/common/models/user.js'); | |
var async = require('async'); | |
var _ = require('lodash'); | |
var debug = require('debug')('loopback:user'); | |
module.exports = function(User) { | |
// extend the builtin user | |
builtinUser(User); | |
// Strip roles property for all none-admins in REST calls | |
User.beforeRemote('**', function(ctx, modelInstance, next) { | |
// no roles in body, nothing to check | |
if(!ctx.req.body.roles) return next(); | |
var userId = _.get(ctx.req, 'accessToken.userId'); | |
User.app.models.Role.isInRole( | |
'admin', | |
{ | |
principalType: User.app.models.RoleMapping.USER, | |
principalId: userId | |
}, | |
function(err, isInRole) { | |
if(err || !isInRole) { | |
debug('Current User has no Admin Role, removing roles from request body'); | |
ctx.req.body.roles = false; | |
return next(err); | |
} | |
next(); | |
} | |
); | |
}); | |
// Update RoleMapping using roles array in request data | |
User.observe('after save', function(ctx, next) { | |
var roles = ctx.instance.roles; | |
// no roles in req-body or false through | |
// access checking | |
if(!roles) return next(); | |
debug('Found roles in data, update users RoleMapping'); | |
var userId = ctx.instance.id; | |
var RoleModel = User.app.models.Role; | |
var RoleMappingModel = User.app.models.RoleMapping; | |
function setRoles(err, currMapping) { | |
if(err) return next(err); | |
async.parallel([ | |
function(cb) { | |
var removeMappingIds = []; | |
currMapping.oldRoleMappings.forEach(function(oldRoleMapping) { | |
if(roles.indexOf(oldRoleMapping.role().name) === -1) { | |
removeMappingIds.push(oldRoleMapping.id); | |
debug('Remove RoleMapping ' + oldRoleMapping.role().name); | |
} | |
}); | |
if(removeMappingIds.length) { | |
// remove obsolete RoleMappings | |
RoleMappingModel.destroyAll({id: {inq:removeMappingIds}}, cb); | |
} else cb(); | |
}, | |
function(cb) { | |
var oldRoleMappingNames = currMapping.oldRoleMappings.map(function(oldRoleMapping) { | |
return oldRoleMapping.role().name; | |
}); | |
var addRoleIds = []; | |
var newNames = []; | |
currMapping.newRoles.forEach(function(newRole) { | |
newNames.push(newRole.name); | |
if(oldRoleMappingNames.indexOf(newRole.name) === -1) { | |
debug('Add RoleMapping '+newRole.name); | |
addRoleIds.push(newRole.id); | |
} | |
}); | |
// remove not existing roles from dataset | |
if(roles.length !== newNames.length) { | |
ctx.instance.roles = newNames; | |
ctx.instance.save(); | |
} | |
// persist new RoleMappings | |
async.each(addRoleIds, function(roleId, cb) { | |
RoleMappingModel.create({ | |
principalId: userId, | |
principalType: 'USER', | |
roleId: roleId | |
}, cb) | |
}, cb); | |
} | |
], next); | |
} | |
// Get current rolemappings | |
async.parallel({ | |
newRoles: RoleModel.find.bind(RoleModel, {where: {name: {inq: roles}}}), | |
oldRoleMappings: RoleMappingModel.find.bind(RoleMappingModel, {where: {principalId: userId, principalType: 'USER'}, include: 'role'}) | |
}, setRoles); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment