Skip to content

Commit

Permalink
Merge b92266e into 231f8dd
Browse files Browse the repository at this point in the history
  • Loading branch information
JuwonAbiola committed Aug 15, 2019
2 parents 231f8dd + b92266e commit b3cf135
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 3 deletions.
8 changes: 8 additions & 0 deletions server/database/migrations/20190730111558-create-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ export default {
type: Sequelize.STRING,
allowNull: true
},
role: {
type: Sequelize.STRING,
allowNull: false
},
level: {
type: Sequelize.INTEGER,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
Expand Down
25 changes: 25 additions & 0 deletions server/database/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,31 @@ export default (sequelize, DataTypes) => {
msg: 'user occupation must contain only letters and/or spaces'
}
}
},
role: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'user',
validate: {
len: {
args: [2, 20],
msg: 'roles must be strings between 2 and 20 chars long'
}
}
},
level: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
validate: {
isInt: {
msg: 'user level count must be an integer'
},
min: {
args: [0],
msg: 'user level must not be less than 0'
}
}
}
});

Expand Down
6 changes: 6 additions & 0 deletions server/database/seeds/20190730180408-my-seed-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default {
email: 'abiola.jz@andela.com',
password:
'$2y$12$3t1adkk7/grjsz2cG5hlXOTO8LwZUmGeG7zs6udoH78MeoPNmXQ.y',
role: 'superadmin',
level: 5,
createdAt: new Date(),
updatedAt: new Date()
},
Expand All @@ -27,6 +29,8 @@ export default {
identifiedBy: 'fullname',
location: 'Lagos, Nigeria',
occupation: 'Software Engineer',
role: 'user',
level: 0,
createdAt: new Date(),
updatedAt: new Date()
},
Expand All @@ -45,6 +49,8 @@ export default {
identifiedBy: 'fullname',
location: 'Lagos, Nigeria',
occupation: 'Software Engineer',
role: 'admin',
level: 4,
createdAt: new Date(),
updatedAt: new Date()
}
Expand Down
16 changes: 16 additions & 0 deletions server/middlewares/authorizeUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { serverResponse } from '../helpers';

/**
* @name authorizeUser
* @param {Integer} allowedLevel the level given access
* @param {Object} response express response object
* @param {Object} next express next function that calls the next middleware
* @returns {Void} it calls the next middleware
*/
export default allowedLevel => async (request, response, next) => {
const { level } = request.user;
if (level < allowedLevel) {
return serverResponse(response, 403, { error: 'unauthorized user' });
}
next();
};
4 changes: 3 additions & 1 deletion server/middlewares/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import validateProfileEdit from './profileValidation';
import checkUserVerification from './checkUserVerification';
import multerUploads from './multer';
import validateResetPassword from './resetPasswordValidation';
import authorizeUser from './authorizeUser';

const middlewares = {
verifyToken,
Expand All @@ -14,7 +15,8 @@ const middlewares = {
validateProfileEdit,
checkUserVerification,
multerUploads,
validateResetPassword
validateResetPassword,
authorizeUser
};

export default middlewares;
7 changes: 6 additions & 1 deletion server/schemas/profileEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@ export default {
location: Joi.string().error(setCustomMessage('user location')),
occupation: Joi.string()
.regex(/^[a-zA-Z ]*$/)
.error(setCustomMessage('user occupation', 'profile edit'))
.error(setCustomMessage('user occupation', 'profile edit')),
role: Joi.string()
.min(2)
.max(20)
.regex(/^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$/)
.error(setCustomMessage('role'))
};
43 changes: 43 additions & 0 deletions test/middlewares/authorizeUser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import middlewares from '../../server/middlewares';

const { authorizeUser } = middlewares;

chai.use(sinonChai);

describe('authorizeUser middleware', () => {
context(
'when an unauthorized user makes tries to access a protected route',
() => {
it('returns an unauthorized error', async () => {
const request = { user: { level: 2 } };
const response = { status() {}, json() {} };
const next = sinon.spy();
const status = sinon.stub(response, 'status').returnsThis();
sinon.stub(response, 'json').returns({});
const authMiddleware = authorizeUser(5);
await authMiddleware(request, response, next);
expect(status).to.calledWith(403);
response.json.restore();
});
}
);

context(
'when an authorized user makes tries to access a protected route',
() => {
it('goes to the next middleware', async () => {
const request = { user: { level: 9 } };
const response = { status() {}, json() {} };
const next = sinon.spy();
sinon.stub(response, 'json').returns({});
const authMiddleware = authorizeUser(5);
await authMiddleware(request, response, next);
expect(next).to.calledOnce;
response.json.restore();
});
}
);
});
4 changes: 3 additions & 1 deletion test/middlewares/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import * as verifyToken from './verifyToken.test';
import * as userValidation from './userValidation.test';
import * as profileValidation from './profileValidation.test';
import * as checkUserVerification from './checkUserVerification.test';
import * as authorizeUser from './authorizeUser.test';

export default {
verifyToken,
userValidation,
profileValidation,
checkUserVerification
checkUserVerification,
authorizeUser
};

0 comments on commit b3cf135

Please sign in to comment.