Skip to content

Instantly share code, notes, and snippets.

@psi-4ward
Created October 20, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save psi-4ward/2eee9b0d67302932bb77 to your computer and use it in GitHub Desktop.
Save psi-4ward/2eee9b0d67302932bb77 to your computer and use it in GitHub Desktop.
Loopback User model with *roles* property support
/**
* 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