From 319f956b5db1cc0301583081bcba1e81d92bdc6d Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Sat, 25 Nov 2017 21:08:51 -0500 Subject: [PATCH 1/8] Created RoleAssignment endpoint --- .../controllers/RoleAssignmentController.js | 57 +++++++++++++++++++ api/v1/controllers/index.js | 3 +- api/v1/index.js | 1 + api/v1/requests/RoleAssignmentRequest.js | 20 +++++++ api/v1/requests/index.js | 3 +- api/v1/services/UserService.js | 7 +++ 6 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 api/v1/controllers/RoleAssignmentController.js create mode 100644 api/v1/requests/RoleAssignmentRequest.js diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js new file mode 100644 index 0000000..90de2ca --- /dev/null +++ b/api/v1/controllers/RoleAssignmentController.js @@ -0,0 +1,57 @@ +const bodyParser = require('body-parser'); + +const UserService = require('../services').UserService; + +const errors = require('../errors'); +const middleware = require('../middleware'); +const RoleAssignmentRequest = require('../requests').RoleAssignmentRequest; +const roles = require('../utils/roles'); + +const router = require('express').Router(); + +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; +} + +//assigns new role and returns updatedUser +function assignNewRole(req, res, next) { + UserService + .findUserById(req.body.id) + .then((assignedUser) => { + if(maxRole(req.user.related('roles').toJSON()) + > ROLE_VALUE_MAP[req.body.role] + && maxRole(req.user.related('roles').toJSON()) + > maxRole(assignedUser.related('roles').toJSON())) { + + UserService.addRole(assignedUser, req.body.role, true) + .then((updatedUser) => { + res.body = updatedUser.toJSON(); + return next(); + }) + .catch((error) => next(error)); + } else { + return next(new errors.UnauthorizedError()); + } + }) + .catch((error) => next(error)); +} + + +router.use(bodyParser.json()); +router.use(middleware.auth); + +router.post('/', middleware.request(RoleAssignmentRequest), middleware.permission(roles.ORGANIZERS), assignNewRole); + +router.use(middleware.response); +router.use(middleware.errors); + +module.exports.assignNewRole = assignNewRole; +module.exports.router = router; diff --git a/api/v1/controllers/index.js b/api/v1/controllers/index.js index 3d641fa..48e8ce5 100644 --- a/api/v1/controllers/index.js +++ b/api/v1/controllers/index.js @@ -13,5 +13,6 @@ module.exports = { RSVPController: require('./RSVPController.js'), StatsController: require('./StatsController.js'), TrackingController: require('./TrackingController.js'), - MailController: require('./MailController.js') + MailController: require('./MailController.js'), + RoleAssignmentController: require('./RoleAssignmentController.js') }; diff --git a/api/v1/index.js b/api/v1/index.js index dc90dd4..21cb9a7 100644 --- a/api/v1/index.js +++ b/api/v1/index.js @@ -37,6 +37,7 @@ v1.use('/stats', controllers.StatsController.router); v1.use('/tracking', controllers.TrackingController.router); v1.use('/mail', controllers.MailController.router); v1.use('/event', controllers.EventController.router); +v1.use('/assign', controllers.RoleAssignmentController.router); // logs resolved requests (the request once processed by various middleware) and outgoing responses v1.use((req, res, next) => { diff --git a/api/v1/requests/RoleAssignmentRequest.js b/api/v1/requests/RoleAssignmentRequest.js new file mode 100644 index 0000000..0caa25e --- /dev/null +++ b/api/v1/requests/RoleAssignmentRequest.js @@ -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; diff --git a/api/v1/requests/index.js b/api/v1/requests/index.js index 1423bb5..bf11949 100644 --- a/api/v1/requests/index.js +++ b/api/v1/requests/index.js @@ -16,5 +16,6 @@ module.exports = { UploadRequest: require('./UploadRequest'), CheckInRequest: require('./CheckInRequest'), RSVPRequest: require('./RSVPRequest'), - UniversalTrackingRequest: require('./UniversalTrackingRequest') + UniversalTrackingRequest: require('./UniversalTrackingRequest'), + RoleAssignmentRequest: require('./RoleAssignmentRequest') }; diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index 51caae8..e807b20 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -3,6 +3,7 @@ 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'); @@ -117,3 +118,9 @@ module.exports.verifyPassword = (user, password) => user module.exports.resetPassword = (user, password) => user .setPassword(password) .then((updated) => updated.save()); + +module.exports.addRole = (user, role, active) => UserRole + .addRole(user, role, active) + .then((updatedUser) => { + return updatedUser; + }); From bf172a33b6e2336d7a24c597d6d6d1d3abb682d6 Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Wed, 29 Nov 2017 20:29:29 -0600 Subject: [PATCH 2/8] Moved maxRole and assignment logic to user service --- .../controllers/RoleAssignmentController.js | 23 ++++--------------- api/v1/services/UserService.js | 19 +++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js index 90de2ca..bc117b4 100644 --- a/api/v1/controllers/RoleAssignmentController.js +++ b/api/v1/controllers/RoleAssignmentController.js @@ -9,31 +9,18 @@ const roles = require('../utils/roles'); const router = require('express').Router(); -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; -} + //assigns new role and returns updatedUser function assignNewRole(req, res, next) { UserService .findUserById(req.body.id) .then((assignedUser) => { - if(maxRole(req.user.related('roles').toJSON()) - > ROLE_VALUE_MAP[req.body.role] - && maxRole(req.user.related('roles').toJSON()) - > maxRole(assignedUser.related('roles').toJSON())) { - + if(UserService.canAssign(req.user, assignedUser, req.body.role)) { UserService.addRole(assignedUser, req.body.role, true) - .then((updatedUser) => { - res.body = updatedUser.toJSON(); + .then((updatedRole) => { + //TODO:get whole user + res.body = updatedRole.toJSON(); return next(); }) .catch((error) => next(error)); diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index e807b20..20c8185 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -7,6 +7,18 @@ const UserRole = require('../models/UserRole'); const errors = require('../errors'); const utils = require('../utils'); +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 * password will be generated for it @@ -119,6 +131,13 @@ module.exports.resetPassword = (user, password) => user .setPassword(password) .then((updated) => updated.save()); +module.exports.canAssign = (user, assignedUser, newRole) => { + return maxRole(user.related('roles').toJSON()) + > ROLE_VALUE_MAP[newRole] + && maxRole(user.related('roles').toJSON()) + > maxRole(assignedUser.related('roles').toJSON()); +}; + module.exports.addRole = (user, role, active) => UserRole .addRole(user, role, active) .then((updatedUser) => { From ad4b67f0306f641232ec7046096d28a07c5f7e4e Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Wed, 29 Nov 2017 20:52:34 -0600 Subject: [PATCH 3/8] Return updated user with its roles --- api/v1/controllers/RoleAssignmentController.js | 12 +++++++++--- api/v1/services/UserService.js | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js index bc117b4..f0b8aa6 100644 --- a/api/v1/controllers/RoleAssignmentController.js +++ b/api/v1/controllers/RoleAssignmentController.js @@ -19,9 +19,15 @@ function assignNewRole(req, res, next) { if(UserService.canAssign(req.user, assignedUser, req.body.role)) { UserService.addRole(assignedUser, req.body.role, true) .then((updatedRole) => { - //TODO:get whole user - res.body = updatedRole.toJSON(); - return next(); + UserService + .findUserById(assignedUser.id) + .then((updatedUser) => { + updatedUserJson = updatedUser.toJSON(); + updatedUserJson.roles = updatedUser.related("roles").toJSON(); + res.body = updatedUserJson; + return next(); + }) + .catch((error) => next(error)); }) .catch((error) => next(error)); } else { diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index 20c8185..dd9daf4 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -131,6 +131,13 @@ module.exports.resetPassword = (user, password) => user .setPassword(password) .then((updated) => updated.save()); +/** + * Adds role to a user + * @param {User} user a User model + * @param {User} assignedUser the assigned User's model + * @param {String} newRole a role to assign to the user + * @return {Boolean} whether user can assign new role to assignedUser + */ module.exports.canAssign = (user, assignedUser, newRole) => { return maxRole(user.related('roles').toJSON()) > ROLE_VALUE_MAP[newRole] @@ -138,6 +145,13 @@ module.exports.canAssign = (user, assignedUser, newRole) => { > maxRole(assignedUser.related('roles').toJSON()); }; +/** + * 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) => { From 12aa6fe80b9905697eb85f035541553ea794514a Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Wed, 29 Nov 2017 20:58:14 -0600 Subject: [PATCH 4/8] Fixed linter errors --- api/v1/controllers/RoleAssignmentController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js index f0b8aa6..e19a64e 100644 --- a/api/v1/controllers/RoleAssignmentController.js +++ b/api/v1/controllers/RoleAssignmentController.js @@ -18,11 +18,11 @@ function assignNewRole(req, res, next) { .then((assignedUser) => { if(UserService.canAssign(req.user, assignedUser, req.body.role)) { UserService.addRole(assignedUser, req.body.role, true) - .then((updatedRole) => { + .then(() => { UserService .findUserById(assignedUser.id) .then((updatedUser) => { - updatedUserJson = updatedUser.toJSON(); + let updatedUserJson = updatedUser.toJSON(); updatedUserJson.roles = updatedUser.related("roles").toJSON(); res.body = updatedUserJson; return next(); From fd8e80452a65226925fe518f1971693950fd9d72 Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Wed, 6 Dec 2017 20:56:22 -0600 Subject: [PATCH 5/8] Level zeros can't be assigned unless they are volunteers --- api/v1/controllers/RoleAssignmentController.js | 3 ++- api/v1/services/UserService.js | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js index e19a64e..d9a0cc5 100644 --- a/api/v1/controllers/RoleAssignmentController.js +++ b/api/v1/controllers/RoleAssignmentController.js @@ -16,7 +16,8 @@ function assignNewRole(req, res, next) { UserService .findUserById(req.body.id) .then((assignedUser) => { - if(UserService.canAssign(req.user, assignedUser, req.body.role)) { + console.log("Can assign:"+UserService.canAssign(req, assignedUser)); + if(UserService.canAssign(req, assignedUser)) { UserService.addRole(assignedUser, req.body.role, true) .then(() => { UserService diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index dd9daf4..a869dcf 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -6,6 +6,7 @@ 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}; @@ -133,16 +134,18 @@ module.exports.resetPassword = (user, password) => user /** * Adds role to a user - * @param {User} user a User model + * @param {Request} request * @param {User} assignedUser the assigned User's model - * @param {String} newRole a role to assign to the user * @return {Boolean} whether user can assign new role to assignedUser */ -module.exports.canAssign = (user, assignedUser, newRole) => { - return maxRole(user.related('roles').toJSON()) - > ROLE_VALUE_MAP[newRole] - && maxRole(user.related('roles').toJSON()) - > maxRole(assignedUser.related('roles').toJSON()); +module.exports.canAssign = (request, assignedUser) => { + return maxRole(request.user.related('roles').toJSON()) + > ROLE_VALUE_MAP[request.body.role] + && maxRole(request.user.related('roles').toJSON()) + > maxRole(assignedUser.related('roles').toJSON()) + && _.isUndefined(request.originUser) + && (maxRole(assignedUser.related('roles').toJSON()) > 0 + || assignedUser.hasRole(roles.VOLUNTEER)); }; /** From 65ada88fbd17f51ad249e2f3cbd06cdfe4380a17 Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Mon, 18 Dec 2017 16:15:02 -0600 Subject: [PATCH 6/8] added testing --- .../controllers/RoleAssignmentController.js | 30 +-- api/v1/services/UserService.js | 14 +- test/user.js | 193 ++++++++++++++++-- 3 files changed, 196 insertions(+), 41 deletions(-) diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js index d9a0cc5..c35b587 100644 --- a/api/v1/controllers/RoleAssignmentController.js +++ b/api/v1/controllers/RoleAssignmentController.js @@ -16,21 +16,23 @@ function assignNewRole(req, res, next) { UserService .findUserById(req.body.id) .then((assignedUser) => { - console.log("Can assign:"+UserService.canAssign(req, assignedUser)); - if(UserService.canAssign(req, assignedUser)) { + if (UserService.canAssign(req.user, assignedUser, req.body.newRole + ,req.originUser)) { + UserService.addRole(assignedUser, req.body.role, true) - .then(() => { - UserService - .findUserById(assignedUser.id) - .then((updatedUser) => { - let updatedUserJson = updatedUser.toJSON(); - updatedUserJson.roles = updatedUser.related("roles").toJSON(); - res.body = updatedUserJson; - return next(); - }) - .catch((error) => next(error)); - }) - .catch((error) => next(error)); + .then(() => { + UserService + .findUserById(assignedUser.id) + .then((updatedUser) => { + let updatedUserJson = updatedUser.toJSON(); + updatedUserJson.roles = updatedUser.related("roles").toJSON(); + res.body = updatedUserJson; + return next(); + }) + .catch((error) => next(error)); + }) + .catch((error) => next(error)); + } else { return next(new errors.UnauthorizedError()); } diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index a869dcf..0fb8927 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -134,16 +134,18 @@ module.exports.resetPassword = (user, password) => user /** * Adds role to a user - * @param {Request} request + * @param {User} u_.isUndefined(originUser)ser 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 = (request, assignedUser) => { - return maxRole(request.user.related('roles').toJSON()) - > ROLE_VALUE_MAP[request.body.role] - && maxRole(request.user.related('roles').toJSON()) +module.exports.canAssign = (user, assignedUser, newRole, originUser) => { + return maxRole(user.related('roles').toJSON()) + > ROLE_VALUE_MAP[newRole] + && maxRole(user.related('roles').toJSON()) > maxRole(assignedUser.related('roles').toJSON()) - && _.isUndefined(request.originUser) + && _.isUndefined(originUser) && (maxRole(assignedUser.related('roles').toJSON()) > 0 || assignedUser.hasRole(roles.VOLUNTEER)); }; diff --git a/test/user.js b/test/user.js index 6c38572..f5c8797 100644 --- a/test/user.js +++ b/test/user.js @@ -5,6 +5,7 @@ const sinon = require('sinon'); const _ = require('lodash'); const errors = require('../api/v1/errors'); +const utils = require('../api/v1/utils'); const UserService = require('../api/v1/services/UserService.js'); const User = require('../api/v1/models/User.js'); @@ -19,7 +20,11 @@ describe('UserService', () => { let testUser; before((done) => { - testUser = { id: 1, email: 'new@example.com', password: 'password123' }; + testUser = { + id: 1, + email: 'new@example.com', + password: 'password123' + }; _createUser = sinon.spy(User, 'create'); _findByEmail = sinon.spy(User, 'findByEmail'); @@ -29,11 +34,11 @@ describe('UserService', () => { tracker.install(); done(); }); - it('creates a new user', function (done) { + it('creates a new user', function(done) { const testUserClone = _.clone(testUser); tracker.on('query', (query) => { - query.response([ '1' ]); + query.response(['1']); }); const user = UserService.createUser(testUserClone.email, testUserClone.password, null); @@ -71,7 +76,10 @@ describe('UserService', () => { let _findByEmail; before((done) => { - const testUser = User.forge({ id: 1, email: 'valid@example.com' }); + const testUser = User.forge({ + id: 1, + email: 'valid@example.com' + }); _findByEmail = sinon.stub(User, 'findByEmail'); @@ -98,7 +106,10 @@ describe('UserService', () => { describe('findUserById', () => { let _findById; before((done) => { - const testUser = User.forge({ id: 1, email: 'new@example.com' }); + const testUser = User.forge({ + id: 1, + email: 'new@example.com' + }); testUser.setPassword('password123'); _findById = sinon.stub(User, 'findById'); @@ -111,10 +122,10 @@ describe('UserService', () => { it('finds existing user', (done) => { const user = UserService.findUserById(1); expect(user).to.eventually.have.deep.property('attributes.id', 1, 'ID should be 1, the searched for ID') - .then(() => { - expect(user).to.eventually.have.deep.property('attributes.email', - 'new@example.com', 'email should be new@example.com').notify(done); -}); + .then(() => { + expect(user).to.eventually.have.deep.property('attributes.email', + 'new@example.com', 'email should be new@example.com').notify(done); + }); }); it('throws exception after searching for non-existent user', (done) => { const user = UserService.findUserById(2); @@ -131,12 +142,15 @@ describe('UserService', () => { let testUser; before((done) => { - testUser = User.forge({ id: 1, email: 'new@example.com' }); + testUser = User.forge({ + id: 1, + email: 'new@example.com' + }); testUser.setPassword('password123') - .then((updatedUser) => { - testUser = updatedUser; - done(); -}); + .then((updatedUser) => { + testUser = updatedUser; + done(); + }); }); @@ -161,16 +175,19 @@ describe('UserService', () => { let testUser; let _save; before((done) => { - testUser = User.forge({ id: 1, email: 'new@example.com' }); + testUser = User.forge({ + id: 1, + email: 'new@example.com' + }); testUser.setPassword('password123') - .then(function(updatedUser){ - testUser = updatedUser; + .then(function(updatedUser) { + testUser = updatedUser; - _save = sinon.stub(User.prototype, 'save'); - _save.withArgs().returns(this); + _save = sinon.stub(User.prototype, 'save'); + _save.withArgs().returns(this); - done(); -}); + done(); + }); }); it('resets password', (done) => { const user = UserService.resetPassword(testUser, 'password456').then((updatedUser) => UserService.verifyPassword(updatedUser, 'password456')); @@ -181,4 +198,138 @@ describe('UserService', () => { done(); }); }); + + describe('canAssign', () => { + let testUserTemplate; + let assignedUserTemplate; + + before((done) => { + testUserTemplate = User.forge({ + id: 1, + email: 'old@example.com' + }); + assignedUserTemplate = User.forge({ + id: 2, + email: 'new@example.com' + }); + + done(); + }); + + it('valid role assignment', (done) => { + let testUser = _.clone(testUserTemplate); + let assignedUser = _.clone(assignedUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + assignedUser.related('roles').add({ + role: utils.roles.VOLUNTEER, + active: 1 + }); + + const result = UserService + .canAssign(testUser, assignedUser, utils.roles.STAFF, undefined); + + expect(result).to.equal(true); + done(); + }); + + it('too high role assignment', (done) => { + let testUser = _.clone(testUserTemplate); + let assignedUser = _.clone(assignedUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + assignedUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + + const result = UserService + .canAssign(testUser, assignedUser, utils.roles.STAFF, undefined); + + expect(result).to.equal(false); + done(); + }); + + it('too low user', (done) => { + let testUser = _.clone(testUserTemplate); + let assignedUser = _.clone(assignedUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.VOLUNTEER, + active: 1 + }); + assignedUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + + const result = UserService + .canAssign(testUser, assignedUser, utils.roles.STAFF, undefined); + + expect(result).to.equal(false); + done(); + }); + + it('non volunteer level zero assignment', (done) => { + let testUser = _.clone(testUserTemplate); + let assignedUser = _.clone(assignedUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + assignedUser.related('roles').add({ + role: utils.roles.ATTENDEE, + active: 1 + }); + + const result = UserService + .canAssign(testUser, assignedUser, utils.roles.STAFF, undefined); + + expect(result).to.equal(false); + done(); + }); + + it('impersonated', (done) => { + let testUser = _.clone(testUserTemplate); + let assignedUser = _.clone(assignedUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + assignedUser.related('roles').add({ + role: utils.roles.VOLUNTEER, + active: 1 + }); + + const result = UserService + .canAssign(testUser, assignedUser, utils.roles.STAFF, testUser); + + expect(result).to.equal(false); + done(); + }); + + it('same user', (done) => { + let testUser = _.clone(testUserTemplate); + + testUser.related('roles').add({ + role: utils.roles.ADMIN, + active: 1 + }); + + const result = UserService + .canAssign(testUser, testUser, utils.roles.STAFF, undefined); + + expect(result).to.equal(false); + done(); + }); + + }); }); From 7e5e07e2a38a0dc172572ab052785a05ba5c22f9 Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Sat, 10 Feb 2018 17:32:26 -0600 Subject: [PATCH 7/8] Moved into user controller --- .../controllers/RoleAssignmentController.js | 53 ------------------- api/v1/controllers/UserController.js | 32 +++++++++++ api/v1/controllers/index.js | 1 - api/v1/index.js | 1 - api/v1/services/UserService.js | 9 ++-- 5 files changed, 35 insertions(+), 61 deletions(-) delete mode 100644 api/v1/controllers/RoleAssignmentController.js diff --git a/api/v1/controllers/RoleAssignmentController.js b/api/v1/controllers/RoleAssignmentController.js deleted file mode 100644 index c35b587..0000000 --- a/api/v1/controllers/RoleAssignmentController.js +++ /dev/null @@ -1,53 +0,0 @@ -const bodyParser = require('body-parser'); - -const UserService = require('../services').UserService; - -const errors = require('../errors'); -const middleware = require('../middleware'); -const RoleAssignmentRequest = require('../requests').RoleAssignmentRequest; -const roles = require('../utils/roles'); - -const router = require('express').Router(); - - - -//assigns new role and returns updatedUser -function assignNewRole(req, res, next) { - UserService - .findUserById(req.body.id) - .then((assignedUser) => { - if (UserService.canAssign(req.user, assignedUser, req.body.newRole - ,req.originUser)) { - - UserService.addRole(assignedUser, req.body.role, true) - .then(() => { - UserService - .findUserById(assignedUser.id) - .then((updatedUser) => { - let updatedUserJson = updatedUser.toJSON(); - updatedUserJson.roles = updatedUser.related("roles").toJSON(); - res.body = updatedUserJson; - return next(); - }) - .catch((error) => next(error)); - }) - .catch((error) => next(error)); - - } else { - return next(new errors.UnauthorizedError()); - } - }) - .catch((error) => next(error)); -} - - -router.use(bodyParser.json()); -router.use(middleware.auth); - -router.post('/', middleware.request(RoleAssignmentRequest), middleware.permission(roles.ORGANIZERS), assignNewRole); - -router.use(middleware.response); -router.use(middleware.errors); - -module.exports.assignNewRole = assignNewRole; -module.exports.router = router; diff --git a/api/v1/controllers/UserController.js b/api/v1/controllers/UserController.js index f4f8125..7100df9 100644 --- a/api/v1/controllers/UserController.js +++ b/api/v1/controllers/UserController.js @@ -8,6 +8,7 @@ const requests = require('../requests'); const scopes = require('../utils/scopes'); const mail = require('../utils/mail'); const roles = require('../utils/roles'); +const errors = require('../errors'); const router = require('express').Router(); @@ -87,6 +88,35 @@ function requestPasswordReset(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(); + }) + .catch((error) => next(error)); + }) + .catch((error) => next(error)); + + } else { + return next(new errors.UnauthorizedError()); + } + }) + .catch((error) => next(error)); +} + + router.use(bodyParser.json()); router.use(middleware.auth); @@ -97,6 +127,8 @@ router.post('/accredited', middleware.request(requests.AccreditedUserCreationReq router.post('/reset', middleware.request(requests.ResetTokenRequest), requestPasswordReset); 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.use(middleware.response); router.use(middleware.errors); diff --git a/api/v1/controllers/index.js b/api/v1/controllers/index.js index 48e8ce5..6e1e0dc 100644 --- a/api/v1/controllers/index.js +++ b/api/v1/controllers/index.js @@ -14,5 +14,4 @@ module.exports = { StatsController: require('./StatsController.js'), TrackingController: require('./TrackingController.js'), MailController: require('./MailController.js'), - RoleAssignmentController: require('./RoleAssignmentController.js') }; diff --git a/api/v1/index.js b/api/v1/index.js index 21cb9a7..dc90dd4 100644 --- a/api/v1/index.js +++ b/api/v1/index.js @@ -37,7 +37,6 @@ v1.use('/stats', controllers.StatsController.router); v1.use('/tracking', controllers.TrackingController.router); v1.use('/mail', controllers.MailController.router); v1.use('/event', controllers.EventController.router); -v1.use('/assign', controllers.RoleAssignmentController.router); // logs resolved requests (the request once processed by various middleware) and outgoing responses v1.use((req, res, next) => { diff --git a/api/v1/services/UserService.js b/api/v1/services/UserService.js index 0fb8927..4e77f72 100644 --- a/api/v1/services/UserService.js +++ b/api/v1/services/UserService.js @@ -141,13 +141,10 @@ module.exports.resetPassword = (user, password) => user * @return {Boolean} whether user can assign new role to assignedUser */ module.exports.canAssign = (user, assignedUser, newRole, originUser) => { - return maxRole(user.related('roles').toJSON()) - > ROLE_VALUE_MAP[newRole] - && maxRole(user.related('roles').toJSON()) - > maxRole(assignedUser.related('roles').toJSON()) + return maxRole(user.related('roles').toJSON()) > ROLE_VALUE_MAP[newRole] + && maxRole(user.related('roles').toJSON()) > maxRole(assignedUser.related('roles').toJSON()) && _.isUndefined(originUser) - && (maxRole(assignedUser.related('roles').toJSON()) > 0 - || assignedUser.hasRole(roles.VOLUNTEER)); + && (maxRole(assignedUser.related('roles').toJSON()) > 0 || assignedUser.hasRole(roles.VOLUNTEER)); }; /** From 6522fcdb9f0aed6d5cc3775f9fb9d52e33d9647f Mon Sep 17 00:00:00 2001 From: shreychowdhary Date: Sat, 10 Feb 2018 18:00:15 -0600 Subject: [PATCH 8/8] Fix minor error --- api/v1/requests/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/requests/index.js b/api/v1/requests/index.js index 9b66975..9745f02 100644 --- a/api/v1/requests/index.js +++ b/api/v1/requests/index.js @@ -17,6 +17,6 @@ module.exports = { CheckInRequest: require('./CheckInRequest'), RSVPRequest: require('./RSVPRequest'), UniversalTrackingRequest: require('./UniversalTrackingRequest'), - RoleAssignmentRequest: require('./RoleAssignmentRequest') + RoleAssignmentRequest: require('./RoleAssignmentRequest'), UserContactInfoRequest: require('./UserContactInfoRequest') };