Skip to content

Commit

Permalink
Merge 5fe3bd2 into 8a0d640
Browse files Browse the repository at this point in the history
  • Loading branch information
Chrismarcel committed Mar 25, 2019
2 parents 8a0d640 + 5fe3bd2 commit 93ddc74
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 25 deletions.
19 changes: 11 additions & 8 deletions server/controllers/user.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import jwt from 'jsonwebtoken';
import db from '../database/models';
import { verifyEmailMarkup,
import {
verifyEmailMarkup,
reactivateAccountMarkup,
passwordResetMarkup,
HelperUtils,
response } from '../utils';
response
} from '../utils';

const { User, History, Article, Follower } = db;

Expand Down Expand Up @@ -272,12 +274,13 @@ export default class Users {
static getUserArticles(userId) {
return Article.findAll({
where: { userId },
attributes: { exclude: [
'id',
'userId',
'totalClaps',
'createdAt',
'updatedAt']
attributes: {
exclude: [
'id',
'userId',
'totalClaps',
'createdAt',
'updatedAt']
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default {
index: {
type: Sequelize.INTEGER,
allowNull: true,
defaultValue: 0
},
totalLikes: {
type: Sequelize.INTEGER,
Expand Down
56 changes: 40 additions & 16 deletions server/middlewares/ValidateUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { check, validationResult } from 'express-validator/check';
import Sequelize from 'sequelize';
import bcrypt from 'bcryptjs';
import models from '../database/models';
import { response, validationErrors } from '../utils';
import { response, validationErrors, HelperUtils } from '../utils';

const { Op } = Sequelize;
const { User } = models;
Expand Down Expand Up @@ -68,26 +68,24 @@ class ValidateUser {
* @param {callback} next - Callback method
* @returns {object} - JSON response object
*/
static validateUserDetails(req, res, next) {
static async validateUserDetails(req, res, next) {
const { username, email } = req.body;
const errorFormatter = ({ msg }) => [msg];
const errorMessages = validationResult(req).formatWith(errorFormatter);

if (!errorMessages.isEmpty()) {
return response(res).badRequest({ errors: errorMessages.mapped() });
}
const userObj = await ValidateUser.isUserUnique(email, username);

const uniqueUser = ValidateUser.isUserUnique(email, username);
return Promise.resolve(uniqueUser).then((result) => {
if (result.length > 0) {
const errors = {};
result.forEach((userDetail) => {
errors[userDetail] = [`${userDetail} already exists.`];
});
return response(res).conflict({ errors });
}
return next();
});
if (userObj.length > 0) {
const errors = {};
userObj.forEach((field) => {
errors[field] = [`${field} already exists.`];
});
return response(res).conflict({ errors });
}
next();
}

/**
Expand All @@ -98,16 +96,24 @@ class ValidateUser {
* @returns {boolean} - If user detail is unique or not
*/
static async isUserUnique(email, username) {
const user = await User.findAll({
const matchedFields = [];
const userObj = await User.findOne({
attributes: ['email', 'username'],
where: {
[Op.or]: [{ email }, { username }]
},
raw: true
});

const existingUserObject = await user;
return user.length > 0 ? Object.keys(existingUserObject[0]) : [];
if (userObj && userObj.email === email) {
matchedFields.push('email');
}

if (userObj && userObj.username === username) {
matchedFields.push('username');
}

return matchedFields;
}

/**
Expand Down Expand Up @@ -198,6 +204,24 @@ class ValidateUser {

next();
}

/**
* @method validateEmail
* @description Validate email format
* @param {object} req - request object
* @param {object} res - response object
* @param {object} next - function to pass to next middleware
* @returns {undefined}
*/
static async validateEmail(req, res, next) {
const { email } = req.body;

if (!HelperUtils.isValidEmail(email)) {
response(res).badRequest({ message: 'invalid email format' });
} else {
next();
}
}
}

export default ValidateUser;
4 changes: 3 additions & 1 deletion server/routes/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ authRoute.get('/users/stats',
Users.getStats);

// Send Timed Reactivation Link To Users Email
authRoute.post('/users/reactivate', Users.sendReactivationLink);
authRoute.post('/users/reactivate',
ValidateUser.validateEmail,
Users.sendReactivationLink);

// Reactivate users account
authRoute.get('/users/reactivate', Users.reactivateUser);
Expand Down
13 changes: 13 additions & 0 deletions server/test/reactivate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ describe('Test Reactivation of account endpoint', () => {
});
});

it('It should return 400 if email format is invalid', (done) => {
chai
.request(app)
.post(sentReactivationLinkURL)
.send({ email: 'invalid.email.format.com' })
.end((err, res) => {
expect(res.status).to.equal(400);
expect(res.body.message).to.be.a('string');
expect(res.body.message).to.equal('invalid email format');
done();
});
});


it('It should return 200 if account has been reactivated', (done) => {
chai
Expand Down
12 changes: 12 additions & 0 deletions server/utils/HelperUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ class HelperUtils {
});
});
}

/**
* @method isValidEmail
* @description Validates an email field
* @param {string} email - users email
* @return {boolean} if email is valid
*/
static isValidEmail(email) {
const emailMatch = /^([A-z0-9]+)([._-]{0,1})([A-z0-9]+)@([A-z0-9-_.]+)\.([A-z]{2,3})$/;
const emailEvaluation = emailMatch.test(email);
return emailEvaluation;
}
}

export default HelperUtils;

0 comments on commit 93ddc74

Please sign in to comment.