From b50ff29ba58613bffcc07042f577e7d89c9d9e4e Mon Sep 17 00:00:00 2001 From: bbaime98 <52517921+bbaime98@users.noreply.github.com> Date: Mon, 17 Feb 2020 16:47:59 +0200 Subject: [PATCH] ft(logout): add log out functionality (#20) - add a log-out route - add a logout function - add logout tests - change authController to userController - change authRoute to userRoutes [Finishes #170947550] --- package-lock.json | 33 +++- package.json | 1 + src/controllers/authController.js | 21 ++- src/index.js | 1 - src/routes/authRoutes.js | 6 +- src/routes/welcome.js | 11 -- src/services/localesServices/locales/en.json | 12 +- src/services/localesServices/locales/fr.json | 11 +- src/swagger/auth.swagger.js | 149 +++++++++++++++++++ src/tests/auth.test.js | 120 +++++++++++++++ src/tests/login.test.js | 57 ------- src/tests/signup.test.js | 58 -------- src/tests/signupMockData.js | 10 -- src/tests/verifyAccount.test.js | 1 - src/utils/Responses.js | 8 - 15 files changed, 335 insertions(+), 164 deletions(-) create mode 100644 src/tests/auth.test.js delete mode 100644 src/tests/login.test.js delete mode 100644 src/tests/signup.test.js delete mode 100644 src/tests/signupMockData.js delete mode 100644 src/utils/Responses.js diff --git a/package-lock.json b/package-lock.json index 65ffcd0..62b0a08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4235,8 +4235,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "indent-string": { "version": "4.0.0", @@ -5094,6 +5093,11 @@ } } }, + "localStorage": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/localStorage/-/localStorage-1.0.4.tgz", + "integrity": "sha512-r35zrihcDiX+dqWlJSeIwS9nrF95OQTgqMFm3FB2D/+XgdmZtcutZOb7t0xXkhOEM8a9kpuu7cc28g1g36I5DQ==" + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -5670,6 +5674,26 @@ "semver": "^5.7.0" } }, + "node-localstorage": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/node-localstorage/-/node-localstorage-2.1.5.tgz", + "integrity": "sha512-DMmdnUxGbDg/vKECZv+4SU3OMKo+TieRNbjncttxEo92IgJIpBfxQJHfD5Oz4nwTYajW4De1wyL9O4HcWeZ90Q==", + "requires": { + "write-file-atomic": "^1.1.4" + }, + "dependencies": { + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + } + } + }, "node-modules-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", @@ -7253,6 +7277,11 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", diff --git a/package.json b/package.json index 6c5380b..a263190 100755 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "express-validator": "^6.4.0", "i18n": "^0.8.5", "jsonwebtoken": "^8.5.1", + "localStorage": "^1.0.4", "path": "^0.12.7", "pg": "^7.18.1", "pg-hstore": "^2.3.3", diff --git a/src/controllers/authController.js b/src/controllers/authController.js index e963c6f..6f1d3b7 100644 --- a/src/controllers/authController.js +++ b/src/controllers/authController.js @@ -1,16 +1,16 @@ import uuid from 'uuid/v4'; import bcrypt from 'bcrypt'; import dotenv from 'dotenv'; +import localStorage from 'localStorage'; import db from '../models'; import sendMsg from '../utils/user-created-email'; import provideToken from '../utils/provideToken'; import Response from '../utils/ResponseHandler'; - dotenv.config(); /** * - * @description Authentication Controller + * @description AuthController Controller * @class AuthController */ export default class AuthController { @@ -46,6 +46,7 @@ export default class AuthController { password: hashedPassword, }); const token = provideToken(user.id, user.isVerified, email); + localStorage.setItem('token', token); sendMsg(email, token, firstName); return Response.signupResponse(res, 201, 'User successfully registered', token); } catch (error) { @@ -59,7 +60,7 @@ export default class AuthController { * @param {Object} req * @param {Object} res * @returns {Object} User - * @memberof authController + * @memberof AuthController */ static async login(req, res) { try { @@ -76,6 +77,7 @@ export default class AuthController { } if (bcrypt.compareSync(password, user.password)) { const token = provideToken(user.dataValues.id, user.dataValues.isVerified); + localStorage.setItem('token', token); return Response.login(res, 200, 'User is successfully logged in', token); } return Response.errorResponse(res, 401, 'Incorrect email or password'); @@ -83,4 +85,17 @@ export default class AuthController { return Response.errorResponse(res, 500, error.message); } } + + /** + * @description logout method + * @static + * @param {Object} req + * @param {Object} res + * @returns {Object} User + * @memberof AuthController + */ + static async logout(req, res) { + localStorage.removeItem('token'); + return Response.login(res, 200, res.__('User is successfully logged out')); + } } diff --git a/src/index.js b/src/index.js index b92a9ed..3c186e9 100755 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,6 @@ const app = express(); app.use(i18n.init); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); - const port = process.env.PORT || 3000; app.use('/api', welcome); diff --git a/src/routes/authRoutes.js b/src/routes/authRoutes.js index 5b1bbad..cac3726 100644 --- a/src/routes/authRoutes.js +++ b/src/routes/authRoutes.js @@ -1,15 +1,15 @@ import express from 'express'; import AuthController from '../controllers/authController'; -import verificationController from '../controllers/verificationController'; -import validateParams from '../validation/validateParams'; import validationResult from '../validation/validationResult'; import signupInputRules from '../validation/validationRules'; - +import verificationController from '../controllers/verificationController'; +import validateParams from '../validation/validateParams'; const authRouter = express.Router(); authRouter.post('/register', signupInputRules, validationResult, AuthController.registerUser); authRouter.get('/verification', validateParams.validateToken, verificationController.verifyAccount); authRouter.post('/login', AuthController.login); +authRouter.get('/logout', AuthController.logout); export default authRouter; diff --git a/src/routes/welcome.js b/src/routes/welcome.js index 0b56dd3..7d61c15 100644 --- a/src/routes/welcome.js +++ b/src/routes/welcome.js @@ -2,17 +2,6 @@ import { Router } from 'express'; const router = Router(); -/** - * @swagger - * /api: - * get: - * description: Display welcome message - * produces: - * - application/json - * responses: - * 200: - * description: Welcome to devRepublic Barefoot Nomad API - */ router.get('/', (req, res) => { res.status(200).json({ message: res.__('Welcome to devRepublic Barefoot Nomad API') diff --git a/src/services/localesServices/locales/en.json b/src/services/localesServices/locales/en.json index 666a23a..3816fc3 100644 --- a/src/services/localesServices/locales/en.json +++ b/src/services/localesServices/locales/en.json @@ -1,7 +1,9 @@ { - "Welcome to devRepublic Barefoot Nomad API": "Welcome to devRepublic Barefoot Nomad API", - "register": "register", - "signup": "signup", - "login": "login", - "logout": "logout" + "Welcome to devRepublic Barefoot Nomad API": "Welcome to devRepublic Barefoot Nomad API", + "register": "register", + "signup": "signup", + "login": "login", + "logout": "logout", + "User is successfully logged out": "User is successfully logged out", + "Login first or create an account if you do not have one": "Login first or create an account if you do not have one" } diff --git a/src/services/localesServices/locales/fr.json b/src/services/localesServices/locales/fr.json index 9f5ebcf..5718b06 100644 --- a/src/services/localesServices/locales/fr.json +++ b/src/services/localesServices/locales/fr.json @@ -1,7 +1,8 @@ { - "Welcome to devRepublic Barefoot Nomad API": "Bienvenue au devRepublic Barefoot Nomad API", - "register": "enregistrer", - "signup": "enregistrer", - "login": "connecter", - "logout": "déconnecter" + "Welcome to devRepublic Barefoot Nomad API": "Bienvenue au devRepublic Barefoot Nomad API", + "register": "enregistrer", + "signup": "enregistrer", + "login": "connecter", + "logout": "déconnecter", + "User is successfully logged out": "l'utilisateur s'est déconnecté avec succès" } diff --git a/src/swagger/auth.swagger.js b/src/swagger/auth.swagger.js index 51f996f..ed56a72 100644 --- a/src/swagger/auth.swagger.js +++ b/src/swagger/auth.swagger.js @@ -128,6 +128,131 @@ * description: Incorrect email or password. * */ +/** + * @swagger + * /: + * get: + * description: Display welcome message + * produces: + * - application/json + * responses: + * 200: + * description: Welcome to devRepublic Barefoot Nomad API + */ +/** + * @swagger + * definitions: + * register: + * type: object + * properties: + * firstName: + * type: string + * lastName: + * type: string + * email: + * type: string + * format: email + * password: + * type: string + * format: password + * required: + * - firstName + * - lastName + * - email + * - password + */ +/** + * @swagger + * /api/v1/auth/register: + * post: + * tags: + * - User + * name: Signup + * summary: Signup a user in a system + * produces: + * - application/json + * consumes: + * - application/json + * parameters: + * - name: body + * in: body + * schema: + * $ref: '#/definitions/register' + * type: object + * properties: + * firstName: + * type: string + * lastName: + * type: string + * email: + * type: string + * password: + * type: string + * format: password + * required: + * - firstName + * - lastName + * - email + * - password + * responses: + * '201': + * description: User created. + * '400': + * description: Bad request. + * '409': + * description: User already exist. + * */ +/** + * @swagger + * definitions: + * login: + * type: object + * properties: + * email: + * type: string + * format: email + * password: + * type: string + * format: password + * required: + * - email + * - password + */ +/** + * @swagger + * /api/v1/auth/login: + * post: + * tags: + * - User + * name: login + * summary: login a user in a system + * produces: + * - application/json + * consumes: + * - application/json + * parameters: + * - name: body + * in: body + * schema: + * $ref: '#/definitions/login' + * type: object + * properties: + * email: + * type: string + * password: + * type: string + * format: password + * required: + * - email + * - password + * responses: + * '200': + * description: User logged in. + * '400': + * description: Bad request. + * '401': + * description: Incorrect email or password. + * */ /** * @swagger * /api/v1/auth/verification/token={token}&email={email}: @@ -155,3 +280,27 @@ * '401': * description: Sorry, you are not authorized to access this page. * */ + +/** + * @swagger + * definitions: + * logout: + * type: object + */ +/** + * @swagger + * /api/v1/auth/logout: + * get: + * tags: + * - User + * name: logout + * summary: Logs a user out + * produces: + * - application/json + * consumes: + * - application/json + * responses: + * '200': + * description: User is successfully logged out + * */ + diff --git a/src/tests/auth.test.js b/src/tests/auth.test.js new file mode 100644 index 0000000..e96b121 --- /dev/null +++ b/src/tests/auth.test.js @@ -0,0 +1,120 @@ +import chai from 'chai'; +import chaiHttp from 'chai-http'; +import index from '../index'; + +const { + expect +} = chai; +chai.use(chaiHttp); +describe('Signup Tests', () => { + it('should return account created sucessfully.', (done) => { + chai.request(index) + .post('/api/v1/auth/register') + .send({ + firstName: 'bienaime', + lastName: 'jeanb', + email: 'aime@andela.com', + password: 'Aime12&*' + }) + .end((err, res) => { + expect(res.body).to.be.an('object'); + expect(res.status).to.equal(201); + expect(res.body.message).to.equal('User successfully registered'); + done(); + }); + }); + it('should return email already exist.', (done) => { + chai.request(index) + .post('/api/v1/auth/register') + .send({ + firstName: 'bienaime', + lastName: 'jeanb', + email: 'aime@andela.com', + password: 'Aime12&*' + }) + .end((err, res) => { + expect(res.body).to.be.an('object'); + expect(res.status).to.equal(409); + expect(res.body.error).to.equal('Email already exists'); + done(); + }); + }); + it('should return Lastname must be atleast 4 characters.', (done) => { + chai.request(index) + .post('/api/v1/auth/register') + .send({ + firstName: 'bienaime', + lastName: 'j', + email: 'aime@andela.com', + password: 'Baime12345$@' + }) + .end((err, res) => { + expect(res.body).to.be.an('object'); + expect(res.status).to.equal(400); + expect(res.body.error).to.equal('Lastname must be atleast 4 characters'); + done(); + }); + }); +}); + +describe('LOGIN feature', () => { + it('should login the user', (done) => { + chai + .request(index) + .post('/api/v1/auth/login') + .send({ + email: 'jean@andela.com', + password: 'Bien@BAR789' + }) + .end((err, res) => { + expect(res.status).to.equal(200); + expect(res.body.status).to.equal(200); + expect(res.body.message).to.equal('User is successfully logged in'); + expect(res.body).to.have.property('data'); + done(); + }); + }); + it('should not login a non-existing user', (done) => { + chai + .request(index) + .post('/api/v1/auth/login') + .send({ + email: 'nonexisting@andela.com', + password: 'Bien@BAR789' + }) + .end((err, res) => { + expect(res.status).to.equal(401); + expect(res.body.status).to.equal(401); + expect(res.body.error).to.equal('Incorrect email or password'); + done(); + }); + }); + it('should not login a user with wrong password', (done) => { + chai + .request(index) + .post('/api/v1/auth/login') + .send({ + email: 'jean@andela.com', + password: 'wrong password' + }) + .end((err, res) => { + expect(res.status).to.equal(401); + expect(res.body.status).to.equal(401); + expect(res.body.error).to.equal('Incorrect email or password'); + done(); + }); + }); +}); + +describe('Logout Tests', () => { + it('should return log out a user', (done) => { + chai.request(index) + .get('/api/v1/auth/logout') + .end((err, res) => { + expect(res.body).to.be.an('object'); + expect(res.status).to.equal(200); + expect(res.body.message).to.equal('User is successfully logged out'); + }); + done(); + }); +}); diff --git a/src/tests/login.test.js b/src/tests/login.test.js deleted file mode 100644 index 4a09396..0000000 --- a/src/tests/login.test.js +++ /dev/null @@ -1,57 +0,0 @@ -import chai from 'chai'; -import chaiHttp from 'chai-http'; -import index from '../index'; - -const { - expect -} = chai; -chai.use(chaiHttp); - -describe('LOGIN feature', () => { - it('should login the user', (done) => { - chai - .request(index) - .post('/api/v1/auth/login') - .send({ - email: 'jean@andela.com', - password: 'Bien@BAR789' - }) - .end((err, res) => { - expect(res.status).to.equal(200); - expect(res.body.status).to.equal(200); - expect(res.body.message).to.equal('User is successfully logged in'); - expect(res.body).to.have.property('data'); - done(); - }); - }); - it('should not login a non-existing user', (done) => { - chai - .request(index) - .post('/api/v1/auth/login') - .send({ - email: 'nonexisting@andela.com', - password: 'Bien@BAR789' - }) - .end((err, res) => { - expect(res.status).to.equal(401); - expect(res.body.status).to.equal(401); - expect(res.body.error).to.equal('Incorrect email or password'); - done(); - }); - }); - it('should not login a user with wrong password', (done) => { - chai - .request(index) - .post('/api/v1/auth/login') - .send({ - email: 'jean@andela.com', - password: 'wrong password' - }) - .end((err, res) => { - expect(res.status).to.equal(401); - expect(res.body.status).to.equal(401); - expect(res.body.error).to.equal('Incorrect email or password'); - done(); - }); - }); -}); diff --git a/src/tests/signup.test.js b/src/tests/signup.test.js deleted file mode 100644 index 400be4e..0000000 --- a/src/tests/signup.test.js +++ /dev/null @@ -1,58 +0,0 @@ -import chai from 'chai'; -import chaiHttp from 'chai-http'; -import index from '../index'; - -const { - expect -} = chai; -chai.use(chaiHttp); -describe('Signup Tests', () => { - it('should return account created sucessfully.', (done) => { - chai.request(index) - .post('/api/v1/auth/register') - .send({ - firstName: 'bienaime', - lastName: 'jeanb', - email: 'aime@andela.com', - password: 'Aime12&*' - }) - .end((err, res) => { - expect(res.body).to.be.an('object'); - expect(res.status).to.equal(201); - expect(res.body.message).to.equal('User successfully registered'); - done(); - }); - }); - it('should return email already exist.', (done) => { - chai.request(index) - .post('/api/v1/auth/register') - .send({ - firstName: 'bienaime', - lastName: 'jeanb', - email: 'aime@andela.com', - password: 'Aime12&*' - }) - .end((err, res) => { - expect(res.body).to.be.an('object'); - expect(res.status).to.equal(409); - expect(res.body.error).to.equal('Email already exists'); - done(); - }); - }); - it('should return Lastname must be atleast 4 characters.', (done) => { - chai.request(index) - .post('/api/v1/auth/register') - .send({ - firstName: 'bienaime', - lastName: 'j', - email: 'aime@andela.com', - password: 'Baime12345$@' - }) - .end((err, res) => { - expect(res.body).to.be.an('object'); - expect(res.status).to.equal(400); - expect(res.body.error).to.equal('Lastname must be atleast 4 characters'); - done(); - }); - }); -}); diff --git a/src/tests/signupMockData.js b/src/tests/signupMockData.js deleted file mode 100644 index 5d2091f..0000000 --- a/src/tests/signupMockData.js +++ /dev/null @@ -1,10 +0,0 @@ -const signupData = [ - { - firstName: 'bienaime', - lastName: 'jeanb', - email: 'aime@andela.com', - password: 'Aime12&*' - } -]; - -export default signupData; diff --git a/src/tests/verifyAccount.test.js b/src/tests/verifyAccount.test.js index 177a0f7..a1cdd0b 100644 --- a/src/tests/verifyAccount.test.js +++ b/src/tests/verifyAccount.test.js @@ -13,7 +13,6 @@ import provideToken from '../utils/provideToken'; const token = provideToken(id, isVerified, email); const wrongToken = provideToken(wrongId, isVerified, wrongEmail); - const { expect } = chai; diff --git a/src/utils/Responses.js b/src/utils/Responses.js deleted file mode 100644 index 5cf71da..0000000 --- a/src/utils/Responses.js +++ /dev/null @@ -1,8 +0,0 @@ - -const response = (res, status, message, data) => res.status(status).json({ - status, - message, - data -}); - -export default response;