Skip to content
This repository has been archived by the owner on Jun 21, 2019. It is now read-only.

Role assignment #169

Open
wants to merge 12 commits into
base: staging
Choose a base branch
from
30 changes: 29 additions & 1 deletion api/v1/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const middleware = require('../middleware');
const requests = require('../requests');
const scopes = require('../utils/scopes');
const roles = require('../utils/roles');
const errors = require('../errors');

const router = require('express').Router();

Expand Down Expand Up @@ -117,7 +118,6 @@ function requestPasswordReset(req, res, next) {
})
.catch((error) => next(error));
}

function updateContactInfo(req, res, next) {
services.UserService.updateContactInfo(req.user, req.body.newEmail)
.then((result) => {
Expand All @@ -128,6 +128,32 @@ function updateContactInfo(req, res, next) {
.catch((error) => next(error));
}

function assignNewRole(req, res, next) {
services.UserService
.findUserById(req.body.id)
.then((assignedUser) => {
if (services.UserService
.canAssign(req.user, assignedUser, req.body.role, req.originUser)) {

services.UserService.addRole(assignedUser, req.body.role, true)
.then(() => {
services.UserService
.findUserById(assignedUser.id)
.then((updatedUser) => {
let updatedUserJson = updatedUser.toJSON();
updatedUserJson.roles = updatedUser.related("roles").toJSON();
res.body = updatedUserJson;
return next();
})
})

} else {
return next(new errors.UnauthorizedError());
}
})
.catch((error) => next(error));
}

router.use(bodyParser.json());
router.use(middleware.auth);

Expand All @@ -139,6 +165,8 @@ router.post('/reset', middleware.request(requests.ResetTokenRequest), requestPas
router.get('/', middleware.permission(roles.NONE, isAuthenticated), getAuthenticatedUser);
router.get('/:id(\\d+)', middleware.permission(roles.HOSTS, isRequester), getUser);
router.get('/email/:email', middleware.permission(roles.HOSTS), getUserByEmail);
router.post('/assign', middleware.request(requests.RoleAssignmentRequest),
middleware.permission(roles.ORGANIZERS), assignNewRole);
router.get('/github/:handle', middleware.permission(roles.HOSTS), getUserByGithubHandle);
router.put('/contactinfo', middleware.request(requests.UserContactInfoRequest),
middleware.permission(roles.NONE, isAuthenticated), updateContactInfo);
Expand Down
20 changes: 20 additions & 0 deletions api/v1/requests/RoleAssignmentRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const roles = require('../utils/roles');
const Request = require('./Request');

const bodyRequired = ['id', 'role'];
const bodyValidations = {
'id': [ 'required', 'integer' ],
'role': ['required', 'string', roles.verifyRole]
};

function RoleAssignmentRequest(headers, body) {
Request.call(this, headers, body);

this.bodyRequired = bodyRequired;
this.bodyValidations = bodyValidations;
}

RoleAssignmentRequest.prototype = Object.create(Request.prototype);
RoleAssignmentRequest.prototype.constructor = RoleAssignmentRequest;

module.exports = RoleAssignmentRequest;
1 change: 1 addition & 0 deletions api/v1/requests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ module.exports = {
CheckInRequest: require('./CheckInRequest'),
RSVPRequest: require('./RSVPRequest'),
UniversalTrackingRequest: require('./UniversalTrackingRequest'),
RoleAssignmentRequest: require('./RoleAssignmentRequest'),
UserContactInfoRequest: require('./UserContactInfoRequest')
};
45 changes: 45 additions & 0 deletions api/v1/services/UserService.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,22 @@ const _Promise = require('bluebird');
const _ = require('lodash');

const User = require('../models/User');
const UserRole = require('../models/UserRole');
const errors = require('../errors');
const utils = require('../utils');
const roles = require('../utils').roles;

const ROLE_VALUE_MAP = {"ADMIN":2, "STAFF":1, "SPONSOR":0, "MENTOR":0, "VOLUNTEER":0, "ATTENDEE":0};

function maxRole(userRoles) {
let max = 0;
userRoles.forEach((roleObj) => {
if(ROLE_VALUE_MAP[roleObj.role] > max) {
max = ROLE_VALUE_MAP[roleObj.role];
}
});
return max;
}

/**
* Creates a user of the specified role. When a password is not specified, a
Expand Down Expand Up @@ -135,6 +149,37 @@ module.exports.resetPassword = (user, password) => user
.setPassword(password)
.then((updated) => updated.save());

/**
* Adds role to a user
* @param {User} user assigning new role
* @param {User} assignedUser the assigned User's model
* @param {Role} newRole the new role
* @param {User} originUser the original user to determine if impersonated
* @return {Boolean} whether user can assign new role to assignedUser
*/
module.exports.canAssign = (user, assignedUser, newRole, originUser) => {
let maxUserRole = maxRole(user.related('roles').toJSON());
let maxAssigneeRole = maxRole(assignedUser.related('roles').toJSON());

return maxUserRole > ROLE_VALUE_MAP[newRole]
&& maxUserRole > maxAssigneeRole
&& _.isUndefined(originUser)
&& (maxAssigneeRole > 0 || assignedUser.hasRole(roles.VOLUNTEER));
};

/**
* Adds role to a user
* @param {User} user a User model
* @param {String} role a role to assign to the user
* @param {Boolean} active a boolean whether new role should be active
* @return {UserRole} the updatedUserRole
*/
module.exports.addRole = (user, role, active) => UserRole
.addRole(user, role, active)
.then((updatedUser) => {
return updatedUser;
});

module.exports.updateContactInfo = (user, newEmail) => {
if(!_.isNull(user.get('password'))) {
const message = 'Cannot update the contact info of a Basic user';
Expand Down
Loading