Skip to content

Commit

Permalink
Feature(Login): user login
Browse files Browse the repository at this point in the history
- creates endpoint for user to login
- gives user a token upon signin
[Finishes#168781679]
  • Loading branch information
alainmateso committed Oct 8, 2019
1 parent 2f278ba commit 4725039
Show file tree
Hide file tree
Showing 16 changed files with 168 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ package-lock.json
# Seeders
src/database/seeders

# Migrations
/src/database/migrations
1 change: 0 additions & 1 deletion package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@babel/plugin-proposal-class-properties": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/register": "^7.4.4",
"@babel/runtime": "^7.6.2",
"babel-watch": "^7.0.0",
"chai": "^4.2.0",
"chai-http": "^4.3.0",
Expand All @@ -61,6 +62,7 @@
"path": "^0.12.7",
"pg": "^7.12.1",
"pg-hstore": "^2.3.3",
"regenerator-runtime": "^0.13.3",
"request": "^2.87.0",
"sequelize": "^5.19.1",
"swagger-jsdoc": "^3.4.0",
Expand Down
26 changes: 26 additions & 0 deletions src/controllers/userController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import jwt from 'jsonwebtoken';
import models from '../database/models';
import responseHelper from '../helpers/responseHelper';
import messages from '../helpers/responseMessages';

class UserController {
static async signIn(req, res) {
const { email, password } = req.body;
const user = await models.users.findOne({ where: { email, password } });
if (!user) {
return responseHelper(res, 400, messages.user.error.LOGIN_FAILURE);
}
if (user.verified === false) {
return responseHelper(res, 400, messages.user.error.VERIFY_FIRST);
}
const userToken = jwt.sign({ email }, process.env.SECRET_KEY, { expiresIn: '1h' });
const userInfo = {
userID: user.id,
username: user.username,
email: user.email,
token: userToken
};
return responseHelper(res, 200, messages.user.success.SUCCESSFUL_LOGIN, userInfo);
}
}
export default UserController;
13 changes: 13 additions & 0 deletions src/database/migrations/20191008073714-addPasswordColumn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

module.exports = {
up: (queryInterface, Sequelize) => queryInterface.addColumn(
'users',
'password',
Sequelize.STRING
),

down: (queryInterface, Sequelize) => queryInterface.removeColumn(
'users',
'password'
)
};
13 changes: 13 additions & 0 deletions src/database/migrations/20191008112757-addVerifiedColumn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

module.exports = {
up: (queryInterface, Sequelize) => queryInterface.addColumn(
'users',
'verified',
Sequelize.BOOLEAN
),

down: (queryInterface, Sequelize) => queryInterface.removeColumn(
'users',
'verified'
)
};
4 changes: 3 additions & 1 deletion src/database/models/users.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module.exports = (sequelize, Datatypes) => {
const Users = sequelize.define('users', {
username: Datatypes.STRING,
email: Datatypes.STRING
email: Datatypes.STRING,
password: Datatypes.STRING,
verified: Datatypes.BOOLEAN
}, {
tableName: 'users'
});
Expand Down
2 changes: 2 additions & 0 deletions src/database/seeders/20191002153158-usersTableSeeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module.exports = {
queryInterface.bulkInsert('users', [{
username: 'johndoe',
email: 'johndoe@test.com',
password: 'default',
verified: false,
createdAt: new Date(),
updatedAt: new Date()
}])
Expand Down
19 changes: 19 additions & 0 deletions src/database/seeders/20191008111708-defaultUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('users', [{
username: 'caretUser',
email: 'user@caretbn.com',
password: 'default',
verified: true,
createdAt: new Date(),
updatedAt: new Date()
}], {});
},

down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('users', null, {});

}
};
1 change: 1 addition & 0 deletions src/helpers/responseHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default (res, status, message, data) => res.status(status).json({ status, message, data });
13 changes: 13 additions & 0 deletions src/helpers/responseMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const messages = {
user: {
success: {
SUCCESSFUL_LOGIN: 'User logged in successfully!'
},
error: {
LOGIN_FAILURE: 'Incorrect email or password!',
VERIFY_FIRST: 'Please verify your email first!',
}
}
};

export default messages;
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// eslint-disable-next-line no-unused-vars
import regeneratorRuntime from 'regenerator-runtime';
import dotenv from 'dotenv';
import express from 'express';
import morgan from 'morgan';
Expand Down
2 changes: 2 additions & 0 deletions src/routes/api/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Router from 'express';
import usersRoutes from './users';
import swaggerRoute from '../swagger-doc';
import user from './userRoutes';


const router = new Router();
router.use('/users', usersRoutes);
router.use('/api-docs', swaggerRoute);
router.use('/', user);

router.use((err, req, res, next) => {
if (err.name === 'ValidationError') {
Expand Down
10 changes: 10 additions & 0 deletions src/routes/api/userRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import express from 'express';
import UserController from '../../controllers/userController';

const { signIn } = UserController;

const router = express.Router();

router.post('/auth/login', signIn);

export default router;
8 changes: 8 additions & 0 deletions src/tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { describe } from 'mocha';
import test from './test';
import userTest from './userTest';

describe('Testing Barefoot Nomad...', () => {
describe('Initial Tests', test);
describe('User Tests', userTest);
});
52 changes: 52 additions & 0 deletions src/tests/userTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import { describe, it } from 'mocha';
import app from '../index';
import messages from '../helpers/responseMessages';


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

const verifiedUser = { email: 'user@caretbn.com', password: 'default' };
const unVerifiedUser = { email: 'johndoe@test.com', password: 'default' };
const invalidData = { email: 'email@email.com', password: 'password' };

describe('User Login Test', () => {
it('it should should return 200 and log in a user successfully ', done => {
chai.request(app)
.post('/api/v1/auth/login')
.send(verifiedUser)
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('status').eql(200);
res.body.should.have.property('message').eql(`${messages.user.success.SUCCESSFUL_LOGIN}`);
done();
});
});
it('it should should return 400 and tell the user that email or password is incorrect ', done => {
chai.request(app)
.post('/api/v1/auth/login')
.send(invalidData)
.end((err, res) => {
res.should.have.status(400);
res.body.should.be.a('object');
res.body.should.have.property('status').eql(400);
res.body.should.have.property('message').eql(`${messages.user.error.LOGIN_FAILURE}`);
done();
});
});
it('it should should return 400 and tell the user to verify first ', done => {
chai.request(app)
.post('/api/v1/auth/login')
.send(unVerifiedUser)
.end((err, res) => {
res.should.have.status(400);
res.body.should.be.a('object');
res.body.should.have.property('status').eql(400);
res.body.should.have.property('message').eql(`${messages.user.error.VERIFY_FIRST}`);
done();
});
});
});

0 comments on commit 4725039

Please sign in to comment.