Skip to content

Commit

Permalink
Merge 7f9d943 into a10e247
Browse files Browse the repository at this point in the history
  • Loading branch information
chuxmykel authored Jul 29, 2019
2 parents a10e247 + 7f9d943 commit 972867b
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 15 deletions.
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"author": "Andela Simulations Programme",
"license": "MIT",
"dependencies": {
"@hapi/joi": "^15.1.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.18.3",
"chalk": "^2.4.2",
Expand Down
17 changes: 17 additions & 0 deletions server/helpers/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Joi from '@hapi/joi';
import utils from './Utilities';

const validate = (object, schema, req, res, next) => {
const { error, value } = Joi.validate(object, schema, { abortEarly: false });

if (error) {
return utils.errorStat(res, 400, error.details.map((detail) => {
const message = detail.message.replace(/"/gi, '');
return message;
}));
}
req.body[Object.keys(req.body)[0]] = value;
return next();
};

export default validate;
40 changes: 40 additions & 0 deletions server/middlewares/inputValidator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
userSchema,
loginSchema,
} from './schema';
import validate from '../helpers/validate';

/**
* @class InputValidator
* @description Validates all user inputs
* @exports InputValidator
*/
class InputValidator {
/**
* @method validateUser
* @description Validates user details on signup
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @param {function} next - The next function to point to the next middleware
* @returns {function} validate() - An execucted validate function
*/
static validateUser(req, res, next) {
const user = { ...req.body.user };
return validate(user, userSchema, req, res, next);
}

/**
* @method validateLogin
* @description Validates user login details on login
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @param {function} next - The next function to point to the next middleware
* @returns {function} validate() - An execucted validate function
*/
static validateLogin(req, res, next) {
const login = { ...req.body.user };
return validate(login, loginSchema, req, res, next);
}
}

export default InputValidator;
82 changes: 82 additions & 0 deletions server/middlewares/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import Joi from '@hapi/joi';

export const userSchema = {
firstname: Joi.string().lowercase().trim().required()
.regex(/^[a-zA-Z]+$/)
.error((errors) => {
errors.forEach((err) => {
switch (err.type) {
case 'string.regex.base':
err.message = 'firstname can only contain letters';
break;
default:
break;
}
});
return errors;
}),
lastname: Joi.string().lowercase().trim().required()
.regex(/^[a-zA-Z]+$/)
.error((errors) => {
errors.forEach((err) => {
switch (err.type) {
case 'string.regex.base':
err.message = 'lastname can only contain letters';
break;
default:
break;
}
});
return errors;
}),
username: Joi.string().trim().min(3).max(16)
.required()
.regex(/^[a-z0-9_-]+$/)
.error((errors) => {
errors.forEach((err) => {
switch (err.type) {
case 'string.regex.base':
err.message = 'usernames can only alphanumeric characters, underscores and hyphens';
break;
default:
break;
}
});
return errors;
}),
email: Joi.string().trim().lowercase().email({ minDomainSegments: 2 })
.required(),
password: Joi.string().min(8).required()
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])/)
.error((errors) => {
errors.forEach((err) => {
switch (err.type) {
case 'string.regex.base':
err.message = 'password must contain at least 1 uppercase, 1 lowercase, 1 number and 1 special character';
break;
default:
break;
}
});
return errors;
}),
};

export const loginSchema = {
email: Joi.string().trim().lowercase().email({ minDomainSegments: 2 })
.required(),
password: Joi.string().min(8).required()
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])/)
.error((errors) => {
errors.forEach((err) => {
switch (err.type) {
case 'string.regex.base':
err.message = 'password must contain at least 1 uppercase, 1 lowercase, 1 number and 1 special character';
break;
default:
break;
}
});
return errors;
}),
};
9 changes: 6 additions & 3 deletions server/routes/user.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import express from 'express';
import UserController from '../controllers/userController';

import InputValidator from '../middlewares/inputValidator';

const userRoute = express();

userRoute.post('/', UserController.signUp);
userRoute.post('/login', UserController.login);
const { signUp, login } = UserController;
const { validateUser, validateLogin } = InputValidator;

userRoute.post('/', validateUser, signUp);
userRoute.post('/login', validateLogin, login);

export default userRoute;
153 changes: 144 additions & 9 deletions server/tests/testData/user.data.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,166 @@
const user = [
// correct details 0
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: 'testusername',
email: 'test@testdomain.testcom',
password: 'ahcommando'
email: 'test@testdomain.com',
password: 'P@ssword123'
}
},
// wrong email 1
{
user: {
email: 'test@testdomain.testcom',
password: 'ahcommando'
firstname: 'test',
lastname: 'testlastname',
username: 'testusername',
email: 'testdomain.com',
password: 'P@ssword123'
}
},
// no firstname 2
{
user: {
firstname: '',
lastname: 'testlastname',
username: 'testusername',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// no lastname 3
{
user: {
firstname: 'test',
lastname: '',
username: 'testusername',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// no username 4
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: '',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// invalid firstname 5
{
user: {
firstname: 'test2019',
lastname: 'testlastname',
username: 'testusername',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// invalid lastname 6
{
user: {
firstname: 'test',
lastname: 'testlastname2019',
username: 'testusername',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// invalid username length < 3 7
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: 'te',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// invalid username length > 16 8
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: 'testusername65281092',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// invalid username characters 9
{
user: {
email: 'wrong@testdomain.testcom',
password: 'ahcommando'
firstname: 'test',
lastname: 'testlastname',
username: 'test@*#jos',
email: 'test@domain.com',
password: 'P@ssword123'
}
},
// correct login details 10
{
user: {
email: 'test@testdomain.testcom',
password: 'ah-noncommando'
email: 'test@testdomain.com',
password: 'P@ssword123'
}
}
},
// wrong login email 11
{
user: {
email: 'wrong@testdomain.com',
password: 'P@ssword123'
}
},
// wrong password 12
{
user: {
email: 'test@testdomain.com',
password: 'P@ssword123ndo'
}
},
// invalid email 13
{
user: {
email: 'testtestdomain.com',
password: 'P@ssword123'
}
},
// weak password 14
{
user: {
email: 'test@testdomain.com',
password: 'password'
}
},
// short password 15
{
user: {
email: 'test@testdomain.com',
password: 'P@s1'
}
},
// short password signup 16
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: 'testusername',
email: 'test@testdomain.com',
password: 'P@s1'
}
},
// weak password signup 17
{
user: {
firstname: 'test',
lastname: 'testlastname',
username: 'testusername',
email: 'test@testdomain.com',
password: 'password'
}
},
];

export default user;
Loading

0 comments on commit 972867b

Please sign in to comment.