Skip to content
This repository has been archived by the owner on May 9, 2021. It is now read-only.

Commit

Permalink
feat(login): implement login functionality
Browse files Browse the repository at this point in the history
- add tests
- add login controllers
- add validations for login

[Finishes #161504670]
  • Loading branch information
augustineezinwa committed Oct 31, 2018
1 parent a7369e8 commit 8066a69
Show file tree
Hide file tree
Showing 8 changed files with 640 additions and 70 deletions.
438 changes: 436 additions & 2 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
"node": "10.11.0"
},
"scripts": {
"test": "mocha test --require babel-core/register --require babel-polyfill --exit --timeout 5000 ./test/**/**/*.test.js",
"test": "mocha test/**/**/* --require babel-core/register --require babel-polyfill --exit --timeout 20000",
"start": "babel-node index.js",
"build": "babel server -d dist",
"cover": "./node_modules/.bin/babel-node node_modules/.bin/istanbul cover node_modules/.bin/_mocha ./test -- --exit",
"cover": "./node_modules/.bin/babel-node node_modules/.bin/istanbul cover node_modules/.bin/_mocha ./test/**/**/* -- --exit",
"coveralls": "npm run cover -- --report lcovonly && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
},
"author": "Andela Simulations Programme",
Expand All @@ -19,6 +19,8 @@
"@sendgrid/mail": "^6.3.1",
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0",
"bcrypt": "^3.0.2",
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"dotenv": "^6.0.0",
Expand All @@ -39,7 +41,7 @@
"pg-hstore": "^2.3.2",
"request": "^2.87.0",
"sequelize": "^4.41.0",
"slug": "^0.9.1",
"slug": "^0.9.2",
"underscore": "^1.9.1"
},
"devDependencies": {
Expand Down
73 changes: 27 additions & 46 deletions routes/api/users.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
const mongoose = require("mongoose");
const router = require("express").Router();
const passport = require("passport");
const User = mongoose.model("User");
import UserController from '../../server/controllers/UserController';
import UserValidation from '../../server/middlewares/UserValidation';

router.get("/user", function(req, res, next) {
User.findById(req.payload.id)
.then(function(user) {
const { validateUserLogin } = UserValidation;
const { userLogin } = UserController;

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

const User = mongoose.model('User');

router.get('/user', (req, res, next) => {
User.findById(req.payload.id)
.then((user) => {
if (!user) {
return res.sendStatus(401);
}
return res.json({ user: user.toAuthJSON() });
})
.catch(next);
.catch(next);
});

router.put("/user", function(req, res, next) {
User.findById(req.payload.id)
.then(function(user) {
router.put('/user', (req, res, next) => {
User.findById(req.payload.id)
.then((user) => {
if (!user) {
return res.sendStatus(401);
}
Expand All @@ -42,46 +48,21 @@ router.put("/user", function(req, res, next) {
return res.json({ user: user.toAuthJSON() });
});
})
.catch(next);
.catch(next);
});

router.post("/users/login", function(req, res, next) {
if (!req.body.user.email) {
return res.status(422).json({ errors: { email: "can't be blank" } });
}
router.post('/users/login', validateUserLogin, userLogin);

if (!req.body.user.password) {
return res.status(422).json({ errors: { password: "can't be blank" } });
}
passport.authenticate("local", { session: false }, function(
err,
user,
info
) {
if (err) {
return next(err);
}
router.post('/users', (req, res, next) => {
const user = new User();

if (user) {
return res.json({ user: user.toAuthJSON() });
} else {
return res.status(422).json(info);
}
})(req, res, next);
});
user.username = req.body.user.username;
user.email = req.body.user.email;
user.setPassword(req.body.user.password);

router.post("/users", function(req, res, next) {
const user = new User();

user.username = req.body.user.username;
user.email = req.body.user.email;
user.setPassword(req.body.user.password);

user.save()
.then(function() {
return res.json({ user: user.toAuthJSON() });
})
.catch(next);
user.save()
.then(() => res.json({ user: user.toAuthJSON() }))
.catch(next);
});

module.exports = router;
46 changes: 46 additions & 0 deletions server/controllers/UserController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import bcrypt from 'bcrypt-nodejs';
import models from '../models';

const { Users } = models;
/**
* @class UserController
* @description Houses operations on the user data.
*/
class UserController {
/**
* @description - This method logs in user and return a token.
* @param {object} req - The request object bearing the email and password.
* @param {object} res - The response object that is returned as json.
* @returns {object} - The object with message.
* @memberOf UserController
* @static
*/
static userLogin(req, res) {
const { email, password } = req.body;
Users.find({
where: email
})
.then((userFound) => {
if (!userFound) {
return res.status(401).json({
errors: {
message: ['Invalid email or password']
}
});
}
if (bcrypt.compareSync(password, userFound.password)) {
const { id } = userFound;
return res.status(200).json({
status: 'success',
message: 'you are logged in',
user: {
userFound,
token: createToken(id, email)
}
});
}
});
}
}

export default UserController;
34 changes: 34 additions & 0 deletions server/middlewares/UserValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @class UserValidation
* @description Helps perform validations on user request body.
*/
class UserValidation {
/**
* @description - This method validates for email and password field.
* @param {object} req - The request object to be validated.
* @param {object} res - Th response object to be sent to user.
* @param {object} next - The callback function to the next middleware.
* @returns {object} - The error object with message.
* @memberOf UserValidation
* @static
*/
static validateUserLogin(req, res) {
const { email, password } = req.body;
if (!email) {
res.status(422).json({
errors: {
message: ['please enter email']
}
});
}
if (!password) {
res.status(422).json({
errors: {
message: ['please enter password']
}
});
}
}
}

export default UserValidation;
2 changes: 1 addition & 1 deletion server/models/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import config from '/config/config.js';
import config from '../config/config';

const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
Expand Down
18 changes: 0 additions & 18 deletions test/sample.test.js

This file was deleted.

91 changes: 91 additions & 0 deletions test/server/controllers/UserController.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import app from '../../../index';

chai.use(chaiHttp);
chai.should();

const loginUrl = '/api/users/login';

describe('Testing Login feature -Integration testng', () => {
it(
'should display error message if user logins with empty field',
(done) => {
chai.request(app)
.post(loginUrl)
.send({
email: '',
password: ''
})
.end((err, res) => {
res.status.should.be.eql(422);
res.body.should.be.eql({
errors: {
message: ['please enter email']
}
});
});
done();
}
);
it(
'should display error message if user logins with empty password',
(done) => {
chai.request(app)
.post(loginUrl)
.send({
email: 'augustineezinwa@gmail.com',
password: ''
})
.end((err, res) => {
res.status.should.be.eql(422);
res.body.should.be.eql({
errors: {
message: ['please enter password']
}
});
});
done();
}
);
it(
'should display error message if user logins with invalid credentials',
(done) => {
chai.request(app)
.post(loginUrl)
.send({
email: 'augustineezinwa@gmail.com',
password: 'fishdonek4'
})
.end((err, res) => {
res.status.should.be.eql(422);
res.body.should.be.eql({
errors: {
message: ['Invalid email or password']
}
});
});
done();
}
);
it(
'should login a user',
(done) => {
chai.request(app)
.post(loginUrl)
.send({
email: 'augustineezinwa@gmail.com',
password: 'fishdonek4'
})
.end((err, res) => {
res.status.should.be.eql(200);
res.body.should.be.eql({
errors: {
message: ['Invalid email or password']
}
});
});
done();
}
);
});

0 comments on commit 8066a69

Please sign in to comment.