From 0237e90b05f4371aab8ca4b8e12a940aea4f7478 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Tue, 12 Feb 2019 16:44:57 +0200 Subject: [PATCH 01/15] feat(profile) create profile -create route -add controller -add middleware --- .gitignore | 1 + app.js | 3 + controllers/ProfileController.js | 29 ++++ controllers/index.js | 5 +- .../migrations/20190205125059-create-user.js | 137 +++++++++--------- database/models/user.js | 7 +- middlewares/passportStrategies.js | 23 +-- package.json | 2 + routes/api/index.js | 3 +- routes/api/user.js | 28 ++++ 10 files changed, 160 insertions(+), 78 deletions(-) create mode 100644 controllers/ProfileController.js create mode 100644 routes/api/user.js diff --git a/.gitignore b/.gitignore index 251b921..c3411c4 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ shrinkwrap.yaml yarn.lock +package-lock.json # Winston logger files error.log diff --git a/app.js b/app.js index 19bd90d..b5ef59e 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,7 @@ import cors from 'cors'; import morgan from 'morgan'; import swaggerUI from 'swagger-ui-express'; import YAML from 'yamljs'; +import cookie from 'cookie-parser'; import methodOverride from 'method-override'; import { joiErrors } from './middlewares'; import routes from './routes'; @@ -14,6 +15,8 @@ const app = express(); const swaggerYAMLDocs = YAML.load('./docs/swagger.yml'); app.use(cors()); +app.use(cookie()); + app.use(morgan('dev')); app.use(express.urlencoded({ extended: false })); app.use(express.json()); diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js new file mode 100644 index 0000000..8ec4716 --- /dev/null +++ b/controllers/ProfileController.js @@ -0,0 +1,29 @@ +import { Op } from 'sequelize'; +import { User } from '../database/models'; + +/** + * @description ProfileContoller class + */ +class ProfileController { + /** + * @author Daniel + * @param {*} req + * @param {*} res + * @returns{*} profile object + */ + static async createProfile(req, res) { + const{ user } = req.body; + const { id } = req.body.currentUser; + const profile = await User.findOne({ + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt','updateAt']}, + where:{id}}); + console.log(profile); + profile.update(user); + return res.status(200).send({ + user: profile.get() + }) + } +} + +export default ProfileController; + diff --git a/controllers/index.js b/controllers/index.js index 5980c8a..9a45d31 100644 --- a/controllers/index.js +++ b/controllers/index.js @@ -1,5 +1,8 @@ import AuthController from './AuthController'; import UserController from './UserController'; import * as MailController from './MailController'; +import ProfileController from './ProfileController'; + +export { AuthController, UserController, MailController, ProfileController }; + -export { AuthController, UserController, MailController }; diff --git a/database/migrations/20190205125059-create-user.js b/database/migrations/20190205125059-create-user.js index 075768b..dbc02c2 100644 --- a/database/migrations/20190205125059-create-user.js +++ b/database/migrations/20190205125059-create-user.js @@ -1,68 +1,73 @@ -module.exports = { - up: (queryInterface, Sequelize) => - queryInterface.createTable('Users', { - id: { - type: Sequelize.UUID, - primaryKey: true, - defaultValue: Sequelize.UUIDV4 - }, - firstName: { - type: Sequelize.STRING - }, - lastName: { - type: Sequelize.STRING - }, - username: { - type: Sequelize.STRING, - allowNull: false, - unique: true - }, - email: { - type: Sequelize.STRING, - allowNull: false, - unique: true - }, - password: { - type: Sequelize.STRING, - allowNull: false - }, - bio: { - type: Sequelize.TEXT - }, - gender: { - type: Sequelize.STRING - }, - birthDate: { - type: Sequelize.DATE - }, - image: { - type: Sequelize.STRING - }, - cover: { - type: Sequelize.STRING - }, - status: { - type: Sequelize.STRING - }, - userType: { - type: Sequelize.STRING, - defaultValue: 'user' - }, - confirmationCode: { - type: Sequelize.STRING - }, - confirmed: { - type: Sequelize.STRING, - defaultValue: 'pending' - }, - createdAt: { - allowNull: false, - type: Sequelize.DATE - }, - updatedAt: { - allowNull: false, - type: Sequelize.DATE - } - }), +module.exports = { + up: (queryInterface, Sequelize) => + queryInterface.createTable('Users', { + id: { + type: Sequelize.UUID, + primaryKey: true, + defaultValue: Sequelize.UUIDV4 + }, + firstName: { + type: Sequelize.STRING + }, + lastName: { + type: Sequelize.STRING + }, + username: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + password: { + type: Sequelize.STRING, + allowNull: false + }, + bio: { + type: Sequelize.TEXT + }, + gender: { + type: Sequelize.STRING + }, + birthDate: { + type: Sequelize.DATE + }, + image: { + type: Sequelize.STRING + }, + cover: { + type: Sequelize.STRING + }, + status: { + type: Sequelize.STRING, + defaultValue: 'active' + }, + following: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + userType: { + type: Sequelize.STRING, + defaultValue: 'user' + }, + confirmationCode: { + type: Sequelize.STRING + }, + confirmed: { + type: Sequelize.STRING, + defaultValue: 'pending' + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }), down: (queryInterface, Sequelize) => queryInterface.dropTable('Users') }; diff --git a/database/models/user.js b/database/models/user.js index 1fd5356..34c729d 100644 --- a/database/models/user.js +++ b/database/models/user.js @@ -43,7 +43,12 @@ module.exports = (sequelize, DataTypes) => { type: DataTypes.STRING }, status: { - type: DataTypes.STRING + type: DataTypes.STRING, + defaultValue: 'active' + }, + following: { + type: DataTypes.BOOLEAN, + defaultValue: false }, userType: { type: DataTypes.STRING, diff --git a/middlewares/passportStrategies.js b/middlewares/passportStrategies.js index 201e22b..322e92b 100644 --- a/middlewares/passportStrategies.js +++ b/middlewares/passportStrategies.js @@ -2,7 +2,7 @@ import bcrypt from 'bcrypt'; import passport from 'passport'; import { Op } from 'sequelize'; import { Strategy as LocalStrategy } from 'passport-local'; -import { Strategy as JWTStrategy } from 'passport-jwt'; +import { Strategy as JWTStrategy, ExtractJwt } from 'passport-jwt'; import 'dotenv/config'; import { User } from '../database/models'; @@ -35,22 +35,27 @@ passport.use( } ) ); - passport.use( 'jwt', new JWTStrategy( { - jwtFromRequest: req => req.cookies.jwt, + jwtFromRequest: ExtractJwt.fromHeader('authorization'), secretOrKey: JWT_SECRET }, - (jwtPayload, done) => { - if (Date.now() > jwtPayload.expires) { - return done('jwt expired'); + async (jwtPayload, done) => { + try { + const user = await User.findOne({ + where : {id: jwtPayload.id} + }); + if (!user) { + return done(null, false, { message: 'user does not exist' }); + } + return done(null, user.get()); + } catch(error) { + return done(error); } - - return done(null, jwtPayload); } ) -); +) export default passport; diff --git a/package.json b/package.json index 04380a4..0a85b9f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint:fix": "prettier-eslint --write '**/*.js'", "start": "npm run migrate:seed && babel-node index.js", "dev": "nodemon index.js --exec 'npm run lint && babel-node'", + "devstart": "nodemon index.js --exec babel-node", "migrate": "node_modules/.bin/sequelize db:migrate:undo:all && node_modules/.bin/sequelize db:migrate", "migrate:seed": "node_modules/.bin/sequelize db:migrate:undo:all && node_modules/.bin/sequelize db:migrate && node_modules/.bin/sequelize db:seed:all", "seed": "node_modules/.bin/sequelize db:seed:all" @@ -24,6 +25,7 @@ "babel-preset-airbnb": "^3.2.0", "bcrypt": "^3.0.3", "celebrate": "^9.0.2", + "cookie-parser": "^1.4.3", "cors": "^2.8.4", "coveralls": "^3.0.2", "dotenv": "^6.0.0", diff --git a/routes/api/index.js b/routes/api/index.js index f72dcd6..c070175 100644 --- a/routes/api/index.js +++ b/routes/api/index.js @@ -1,8 +1,9 @@ import express from 'express'; import users from './users'; +import user from './user'; const router = express.Router(); router.use('/users', users); - +router.use('/user', user); export default router; diff --git a/routes/api/user.js b/routes/api/user.js new file mode 100644 index 0000000..63d48db --- /dev/null +++ b/routes/api/user.js @@ -0,0 +1,28 @@ +import express from 'express'; +import passport from 'passport'; +import { ProfileController } from '../../controllers'; + + +const router = express.Router(); + +router.put('/', (req, res, next) => { + passport.authenticate('jwt', (err, user, info) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + if (!user) { const status = info.message === 'user does not exist'? 404:401; + return res.status(status).send({ errors: { + body: [info.message] + }}); } + req.logIn(user,{ session: false }, (err) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + req.body.currentUser = user; + return next(); + }); + })(req, res, next); + }, ProfileController.createProfile); + + +export default router; \ No newline at end of file From e4e1a34cb98e94fe71a1ccdb5b5e9958c21f3151 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Wed, 13 Feb 2019 19:25:48 +0200 Subject: [PATCH 02/15] feat(profile) create profile -add request body validation -add some test --- __tests__/routes/profile.test.js | 109 +++++++++++++++++++++++++++++++ controllers/AuthController.js | 7 ++ controllers/ProfileController.js | 20 ++++-- package-lock.json | 9 +++ routes/api/user.js | 8 ++- routes/validators/index.js | 3 +- routes/validators/user.js | 24 +++++++ 7 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 __tests__/routes/profile.test.js create mode 100644 routes/validators/user.js diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js new file mode 100644 index 0000000..a1027f6 --- /dev/null +++ b/__tests__/routes/profile.test.js @@ -0,0 +1,109 @@ +import request from 'supertest'; +import { User } from '../../database/models'; +import { signupUser } from '../mocks/db.json'; +import { urlPrefix } from '../mocks/variables.json'; +import app from '../../app'; + +let testUserToken; +describe('Profile', () => { + beforeAll(async () => { + const { body } = await request(app) + .post(`${urlPrefix}/users`) + .send({ user: { + username: signupUser.username, + email: signupUser.email, + password: signupUser.password + } }); + testUserToken = body.user.token; + }); + + afterAll(async () => { + await User.destroy({ + where: { email: signupUser.email } + }); + }); + + test('create profile', async () => { + expect.assertions(10); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe(profile.firstName); + expect(res.body.user.lastName).toBe(profile.lastName); + expect(res.body.user.username).toBe(profile.username); + expect(res.body.user.email).toBe(profile.email); + expect(res.body.user.bio).toBe(profile.bio); + expect(res.body.user.gender).toBe(profile.gender); + expect(res.body.user.birthDate).toBeDefined(); + expect(res.body.user.image).toBe(profile.image); + expect(res.body.user.cover).toBe(profile.cover); + }); + test('create profile without --token', async () => { + expect.assertions(1); + await User.destroy({ + where: { email: signupUser.email } + }); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + }); + + test('create profile with --unexisting user', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(404); + expect(res.body.errors.body).toBeDefined(); + }); + +}); \ No newline at end of file diff --git a/controllers/AuthController.js b/controllers/AuthController.js index 2b579c4..dbee532 100644 --- a/controllers/AuthController.js +++ b/controllers/AuthController.js @@ -42,6 +42,7 @@ class AuthController { return res.status(401).json({ status: 401, message: 'Please try again' }); } +<<<<<<< HEAD await sendEmailConfirmationLink({ ...userModel.get() }); const { password, confirmationCode, ...userData } = userModel.get(); @@ -49,6 +50,12 @@ class AuthController { return res.status(201).json({ status: 201, message: 'Account created sucessfully. Please check your email for confirmation', +======= + const { password, ...userData } = userModel.get(); + return res.status(201).json({ + status: 201, + message: 'Account created sucessfully', +>>>>>>> feat(profile) create profile user: { ...userData, token } }); } diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 8ec4716..f442b95 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,4 +1,3 @@ -import { Op } from 'sequelize'; import { User } from '../database/models'; /** @@ -9,19 +8,28 @@ class ProfileController { * @author Daniel * @param {*} req * @param {*} res - * @returns{*} profile object + * @returns{*} user object */ static async createProfile(req, res) { const{ user } = req.body; - const { id } = req.body.currentUser; + const { id } = req.currentUser; + try { const profile = await User.findOne({ - attributes:{ exclude: ['password', 'status', 'following','userType','createdAt','updateAt']}, + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); - console.log(profile); - profile.update(user); + profile.update({updateAt: new Date(),...user}); return res.status(200).send({ user: profile.get() }) + } catch(error) { + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) + } } } diff --git a/package-lock.json b/package-lock.json index 3e13b4f..8ec2821 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2432,6 +2432,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, + "cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", diff --git a/routes/api/user.js b/routes/api/user.js index 63d48db..3adca5e 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -1,6 +1,8 @@ import express from 'express'; import passport from 'passport'; +import { celebrate } from 'celebrate'; import { ProfileController } from '../../controllers'; +import { profileValidator } from '../validators' const router = express.Router(); @@ -18,11 +20,13 @@ router.put('/', (req, res, next) => { if (err) { return res.status(520).send({errors: { body:[err.message] }}); } - req.body.currentUser = user; + req.currentUser = user; return next(); }); })(req, res, next); - }, ProfileController.createProfile); + }, + celebrate({ body: profileValidator }), + ProfileController.createProfile); export default router; \ No newline at end of file diff --git a/routes/validators/index.js b/routes/validators/index.js index 6835db6..1bb2e27 100644 --- a/routes/validators/index.js +++ b/routes/validators/index.js @@ -1,3 +1,4 @@ import authValidator from './auth'; +import profileValidator from './user'; -export { authValidator }; +export { authValidator, profileValidator}; diff --git a/routes/validators/user.js b/routes/validators/user.js new file mode 100644 index 0000000..dfcc247 --- /dev/null +++ b/routes/validators/user.js @@ -0,0 +1,24 @@ +import { Joi } from 'celebrate'; + +const profile = { + user: Joi.object().keys({ + username: Joi.string() + .trim(), + firstName: Joi.string() + .min(3), + lastName: Joi.string() + .min(3), + email: Joi.string() + .email() + .trim(), + bio: Joi.string() + .min(20), + gender: Joi.string() + .max(6), + birthDate: Joi.date(), + image: Joi.string(), + cover: Joi.string(), + }) + }; + + export default profile; \ No newline at end of file From a25a29a5e3ac561524b011c7e88d5bcedbe145e2 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 13:50:34 +0200 Subject: [PATCH 03/15] feat(profile) create profile - add more test - enable user to use taken username and email --- __tests__/mocks/db.json | 13 +- __tests__/routes/profile.test.js | 147 +++++++--- controllers/AuthController.js | 7 - controllers/ProfileController.js | 89 +++++- package-lock.json | 453 +++++++++++-------------------- routes/api/user.js | 5 - 6 files changed, 352 insertions(+), 362 deletions(-) diff --git a/__tests__/mocks/db.json b/__tests__/mocks/db.json index 08cf944..6d52d51 100644 --- a/__tests__/mocks/db.json +++ b/__tests__/mocks/db.json @@ -14,5 +14,16 @@ "id": "578c8188-cba6-45f6-842f-8d80c247b818", "username": "oemapp", "email": "oemapp.dev@gmail.com" + }, + "profile":{ + "firstName": "John", + "lastName": "Doe", + "username": "doe201", + "email": "john.doe@andela.com", + "bio": "I am software at Andela", + "gender": "Male", + "birthDate": "12 June 1999", + "image": "https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg", + "cover": "https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg" } -} +} \ No newline at end of file diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index a1027f6..8c74553 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -1,9 +1,12 @@ import request from 'supertest'; +import jwt from 'jsonwebtoken'; import { User } from '../../database/models'; -import { signupUser } from '../mocks/db.json'; +import { signupUser, profile } from '../mocks/db.json'; import { urlPrefix } from '../mocks/variables.json'; import app from '../../app'; +const { JWT_SECRET } = process.env; + let testUserToken; describe('Profile', () => { beforeAll(async () => { @@ -21,21 +24,13 @@ describe('Profile', () => { await User.destroy({ where: { email: signupUser.email } }); + await User.destroy({ + where: { email: profile.email } + }) }); - test('create profile', async () => { + test('should create profile', async () => { expect.assertions(10); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) @@ -54,22 +49,73 @@ describe('Profile', () => { expect(res.body.user.image).toBe(profile.image); expect(res.body.user.cover).toBe(profile.cover); }); - test('create profile without --token', async () => { - expect.assertions(1); + test('should not create profile with --taken email and username', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email and username are already taken'); + }); + test('should not create profile with --taken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + test('should not create profile with --taken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + test('should not create profile with --taken username and untaken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username, + email: 'papasava@email.com' + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + test('should not create profile with --taken email and untaken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: 'papasava', + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + test('should not create profile without --token', async () => { + expect.assertions(2); await User.destroy({ - where: { email: signupUser.email } + where: { email: 'john.doe@andela.com' } }); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .send({user: { @@ -77,33 +123,52 @@ describe('Profile', () => { }}) expect(res.status).toBe(401); + expect(res.body.errors.body[0]).toBe('No auth token'); }); - test('create profile with --unexisting user', async () => { + test('should not create profile with --unexisting user', async () => { expect.assertions(2); await User.destroy({ where: { email: signupUser.email } }); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) .send({user: { ...profile }}) - expect(res.status).toBe(404); expect(res.body.errors.body).toBeDefined(); }); - + test('should not create profile with --malformed token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', 'thgdihueh-jz') + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body).toBeDefined(); + }); + test('should not create profile with --incorrect token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', token) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(520); + expect(res.body.errors.body).toBeDefined(); + }); }); \ No newline at end of file diff --git a/controllers/AuthController.js b/controllers/AuthController.js index dbee532..2b579c4 100644 --- a/controllers/AuthController.js +++ b/controllers/AuthController.js @@ -42,7 +42,6 @@ class AuthController { return res.status(401).json({ status: 401, message: 'Please try again' }); } -<<<<<<< HEAD await sendEmailConfirmationLink({ ...userModel.get() }); const { password, confirmationCode, ...userData } = userModel.get(); @@ -50,12 +49,6 @@ class AuthController { return res.status(201).json({ status: 201, message: 'Account created sucessfully. Please check your email for confirmation', -======= - const { password, ...userData } = userModel.get(); - return res.status(201).json({ - status: 201, - message: 'Account created sucessfully', ->>>>>>> feat(profile) create profile user: { ...userData, token } }); } diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index f442b95..23709a1 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -4,31 +4,92 @@ import { User } from '../database/models'; * @description ProfileContoller class */ class ProfileController { - /** - * @author Daniel - * @param {*} req - * @param {*} res - * @returns{*} user object - */ + /** + * @author Daniel + * @param {*} req + * @param {*} res + * @returns{*} user object + */ static async createProfile(req, res) { const{ user } = req.body; const { id } = req.currentUser; + const{ email, username } = req.body.user; + if (email || username) { + let message; + let errorMessage; + if (email && username ){ + try { + const emailOwner = await User.findOne({ + where:{email} + }) + const usernameOwner = await User.findOne({ + where:{username} + }) + if(emailOwner && usernameOwner){ + message = 'email and username are'; + } else if(emailOwner){ + message = 'email is'; + } else if(usernameOwner){ + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } else if(email) { + try { + const emailOwner = await User.findOne({ + where:{email} + }); + if(emailOwner){ + message = 'email is'; + } + } catch(error) { + errorMessage = error.message; + } + }else if(username){ + try { + const usernameOwner = await User.findOne({ + where:{username} + }); + if(usernameOwner){ + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } + if (message) { + return res.status(409).send({ + errors:{ + body:[`${message} already taken`] + } + }); + } if(errorMessage) { + return res.status(520).send({ + errors:{ + body:[ + errorMessage + ] + } + }); + } + } try { const profile = await User.findOne({ attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); profile.update({updateAt: new Date(),...user}); return res.status(200).send({ - user: profile.get() + user: profile.get() }) } catch(error) { - return res.status(520).send({ - errors:{ - body:[ - error.message - ] - } - }) + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) } } } diff --git a/package-lock.json b/package-lock.json index 8ec2821..4ed2080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -838,9 +838,9 @@ "integrity": "sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==" }, "@types/node": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.0.tgz", - "integrity": "sha512-ry4DOrC+xenhQbzk1iIPzCZGhhPGEFv7ia7Iu6XXSLVluiJIe9FfG7Iu3mObH9mpxEXCWLCMU4JWbCCR9Oy1Zg==" + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.3.tgz", + "integrity": "sha512-DMiqG51GwES/c4ScBY0u5bDlH44+oY8AeYHjY1SGCWidD7h08o1dfHue/TGK7REmif2KiJzaUskO+Q0eaeZ2fQ==" }, "@types/request": { "version": "2.48.1", @@ -1364,23 +1364,19 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "bundled": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "bundled": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "bundled": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -1388,13 +1384,11 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "bundled": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1402,69 +1396,57 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + "bundled": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "bundled": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "bundled": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "bundled": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, "requires": { "ms": "2.0.0" } }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "bundled": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "bundled": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + "bundled": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "requires": { "minipass": "^2.2.1" } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "bundled": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -1478,8 +1460,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "bundled": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1491,29 +1472,25 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "bundled": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "bundled": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "requires": { "minimatch": "^3.0.4" } }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1521,44 +1498,37 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "bundled": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "bundled": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "bundled": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "bundled": true }, "minipass": { "version": "2.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz", - "integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1566,41 +1536,35 @@ "dependencies": { "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + "bundled": true } } }, "minizlib": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz", - "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==", + "bundled": true, "requires": { "minipass": "^2.2.1" } }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "bundled": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "bundled": true, "requires": { "debug": "^2.1.2", "iconv-lite": "^0.4.4", @@ -1609,8 +1573,7 @@ }, "node-pre-gyp": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "bundled": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -1626,8 +1589,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -1635,13 +1597,11 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==" + "bundled": true }, "npm-packlist": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz", - "integrity": "sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==", + "bundled": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -1649,8 +1609,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -1660,36 +1619,30 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "bundled": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "bundled": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "bundled": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -1697,18 +1650,15 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "bundled": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "bundled": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -1718,15 +1668,13 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "bundled": true } } }, "readable-stream": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", - "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1739,46 +1687,38 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "bundled": true, "requires": { "glob": "^7.0.5" } }, "safe-buffer": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "bundled": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "bundled": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "bundled": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "bundled": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "bundled": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1787,29 +1727,25 @@ }, "string_decoder": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "bundled": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "bundled": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -1822,33 +1758,28 @@ "dependencies": { "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + "bundled": true } } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "bundled": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "bundled": true, "requires": { "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "bundled": true } } }, @@ -2433,9 +2364,9 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, "cookie-parser": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", - "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", + "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", "requires": { "cookie": "0.3.1", "cookie-signature": "1.0.6" @@ -2778,9 +2709,9 @@ }, "dependencies": { "@types/node": { - "version": "10.12.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.25.tgz", - "integrity": "sha512-IcvnGLGSQFDvC07Bz2I8SX+QKErDZbUdiQq7S2u3XyzTyJfUmT0sWJMbeQkMzpTAkO7/N7sZpW/arUM2jfKsbQ==" + "version": "10.12.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.26.tgz", + "integrity": "sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg==" } } }, @@ -3811,25 +3742,21 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "bundled": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "bundled": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "bundled": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -3838,13 +3765,11 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "bundled": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3852,35 +3777,29 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "bundled": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "bundled": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "bundled": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "bundled": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, "optional": true, "requires": { "ms": "2.0.0" @@ -3888,26 +3807,22 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "bundled": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "bundled": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bundled": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -3915,14 +3830,12 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -3937,8 +3850,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "bundled": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -3951,14 +3863,12 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "bundled": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "bundled": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -3966,8 +3876,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -3975,8 +3884,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "optional": true, "requires": { "once": "^1.3.0", @@ -3985,46 +3893,39 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "bundled": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "bundled": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "bundled": true }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4032,8 +3933,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "bundled": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -4041,22 +3941,19 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "bundled": true, "optional": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "bundled": true, "optional": true, "requires": { "debug": "^2.1.2", @@ -4066,8 +3963,7 @@ }, "node-pre-gyp": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", - "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", + "bundled": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -4084,8 +3980,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "optional": true, "requires": { "abbrev": "1", @@ -4094,14 +3989,12 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", + "bundled": true, "optional": true }, "npm-packlist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz", - "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", + "bundled": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -4110,8 +4003,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -4122,39 +4014,33 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "bundled": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -4163,20 +4049,17 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "bundled": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -4187,16 +4070,14 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "bundled": true, "optional": true } } }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -4210,8 +4091,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "bundled": true, "optional": true, "requires": { "glob": "^7.1.3" @@ -4219,43 +4099,36 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "bundled": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "bundled": true, "optional": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "bundled": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4264,8 +4137,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -4273,22 +4145,19 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bundled": true, "optional": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "bundled": true, "optional": true, "requires": { "chownr": "^1.1.1", @@ -4302,14 +4171,12 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "bundled": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "bundled": true, "optional": true, "requires": { "string-width": "^1.0.2 || 2" @@ -4317,13 +4184,11 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "bundled": true }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + "bundled": true } } }, @@ -4475,12 +4340,12 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "source-map": { @@ -5102,12 +4967,12 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } } } @@ -7959,9 +7824,9 @@ } }, "realpath-native": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", - "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", "dev": true, "requires": { "util.promisify": "^1.0.0" @@ -9723,11 +9588,11 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "readable-stream": { diff --git a/routes/api/user.js b/routes/api/user.js index 3adca5e..4f4945c 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -16,13 +16,8 @@ router.put('/', (req, res, next) => { return res.status(status).send({ errors: { body: [info.message] }}); } - req.logIn(user,{ session: false }, (err) => { - if (err) { return res.status(520).send({errors: { - body:[err.message] - }}); } req.currentUser = user; return next(); - }); })(req, res, next); }, celebrate({ body: profileValidator }), From 37c5e47198c05fd3b2626c7dd900f2e9667bb700 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 16:02:56 +0200 Subject: [PATCH 04/15] feat(profile) create profile - add confirmation when user change email - add test ' --- __tests__/routes/profile.test.js | 18 ++++++++++++++++-- controllers/ProfileController.js | 17 ++++++++++++++--- middlewares/index.js | 3 ++- middlewares/verifyJwt.js | 17 +++++++++++++++++ package.json | 1 + routes/api/user.js | 18 +++--------------- 6 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 middlewares/verifyJwt.js diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index 8c74553..da309ef 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -29,8 +29,8 @@ describe('Profile', () => { }) }); - test('should create profile', async () => { - expect.assertions(10); + test('should create profile and send confirmation when email is provided', async () => { + expect.assertions(11); const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) @@ -39,6 +39,7 @@ describe('Profile', () => { }}) expect(res.status).toBe(200); + expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); expect(res.body.user.firstName).toBe(profile.firstName); expect(res.body.user.lastName).toBe(profile.lastName); expect(res.body.user.username).toBe(profile.username); @@ -49,6 +50,19 @@ describe('Profile', () => { expect(res.body.user.image).toBe(profile.image); expect(res.body.user.cover).toBe(profile.cover); }); + test('should create profile and not send confirmation email when email is not provided', async () => { + expect.assertions(3); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + firstName: 'Peter' + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe('Peter'); + expect(res.body.message).toBe('The information was updated successful'); + }); test('should not create profile with --taken email and username', async () => { expect.assertions(2); const res = await request(app) diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 23709a1..3f98b99 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,5 +1,6 @@ +import uuid from 'uuid'; import { User } from '../database/models'; - +import { sendEmailConfirmationLink } from './MailController'; /** * @description ProfileContoller class */ @@ -78,9 +79,19 @@ class ProfileController { const profile = await User.findOne({ attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); - profile.update({updateAt: new Date(),...user}); + profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); + let message; + if(user.email){ + await sendEmailConfirmationLink({ ...profile.get() }); + message = 'Your email is changed. Please check your email for confirmation' + }else { + message = 'The information was updated successful' + } + const{ confirmationCode, ...userData } = profile.get(); return res.status(200).send({ - user: profile.get() + statu: 200, + message, + user: userData }) } catch(error) { return res.status(520).send({ diff --git a/middlewares/index.js b/middlewares/index.js index cc0df35..f52c554 100644 --- a/middlewares/index.js +++ b/middlewares/index.js @@ -1,4 +1,5 @@ import joiErrors from './joiErrors'; import passportStrategies from './passportStrategies'; +import verifyJwt from './verifyJwt'; -export { joiErrors, passportStrategies }; +export { joiErrors, passportStrategies, verifyJwt }; diff --git a/middlewares/verifyJwt.js b/middlewares/verifyJwt.js new file mode 100644 index 0000000..78de5a6 --- /dev/null +++ b/middlewares/verifyJwt.js @@ -0,0 +1,17 @@ +import passport from 'passport'; + +const verifyJwt = (req,res,next) =>{ + passport.authenticate('jwt', (err, user, info) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + if (!user) { const status = info.message === 'user does not exist'? 404:401; + return res.status(status).send({ errors: { + body: [info.message] + }}); } + req.currentUser = user; + return next(); + })(req, res, next); +} + +export default verifyJwt; \ No newline at end of file diff --git a/package.json b/package.json index 0a85b9f..ba3f5a0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "slug": "^0.9.3", "swagger-ui-express": "^4.0.2", "underscore": "^1.9.1", + "uuid": "^3.3.2", "winston": "^3.2.1", "yamljs": "^0.3.0" }, diff --git a/routes/api/user.js b/routes/api/user.js index 4f4945c..6c668aa 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -1,25 +1,13 @@ import express from 'express'; -import passport from 'passport'; import { celebrate } from 'celebrate'; import { ProfileController } from '../../controllers'; -import { profileValidator } from '../validators' +import { profileValidator } from '../validators'; +import { verifyJwt } from '../../middlewares'; const router = express.Router(); -router.put('/', (req, res, next) => { - passport.authenticate('jwt', (err, user, info) => { - if (err) { return res.status(520).send({errors: { - body:[err.message] - }}); } - if (!user) { const status = info.message === 'user does not exist'? 404:401; - return res.status(status).send({ errors: { - body: [info.message] - }}); } - req.currentUser = user; - return next(); - })(req, res, next); - }, +router.put('/', verifyJwt, celebrate({ body: profileValidator }), ProfileController.createProfile); From b7dd2f411610318cb2311205c79248961f4ec59e Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 17:49:02 +0200 Subject: [PATCH 05/15] feat(profile) create profile -add new line -solved eslint errors --- __tests__/routes/profile.test.js | 2 +- controllers/ProfileController.js | 149 +++++++++++++++---------------- middlewares/verifyJwt.js | 4 +- package-lock.json | 16 ++-- routes/api/user.js | 2 +- 5 files changed, 86 insertions(+), 87 deletions(-) diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index da309ef..18a73cb 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -185,4 +185,4 @@ describe('Profile', () => { expect(res.status).toBe(520); expect(res.body.errors.body).toBeDefined(); }); -}); \ No newline at end of file +}); diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 3f98b99..1815e0d 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -12,98 +12,97 @@ class ProfileController { * @returns{*} user object */ static async createProfile(req, res) { - const{ user } = req.body; - const { id } = req.currentUser; - const{ email, username } = req.body.user; - if (email || username) { - let message; - let errorMessage; - if (email && username ){ + const { user } = req.body; + const { id } = req.currentUser; + const { email, username } = req.body.user; + if (email || username) { + let message; + let errorMessage; + if (email && username ) { + try { + const emailOwner = await User.findOne({ + where:{email} + }) + const usernameOwner = await User.findOne({ + where:{username} + }) + if (emailOwner && usernameOwner) { + message = 'email and username are'; + } else if (emailOwner) { + message = 'email is'; + } else if (usernameOwner) { + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } else if (email) { try { const emailOwner = await User.findOne({ where:{email} - }) - const usernameOwner = await User.findOne({ - where:{username} - }) - if(emailOwner && usernameOwner){ - message = 'email and username are'; - } else if(emailOwner){ + }); + if(emailOwner){ message = 'email is'; - } else if(usernameOwner){ - message = 'username is'; } } catch(error) { errorMessage = error.message; } - } else if(email) { - try { - const emailOwner = await User.findOne({ - where:{email} - }); - if(emailOwner){ - message = 'email is'; - } - } catch(error) { - errorMessage = error.message; - } - }else if(username){ - try { - const usernameOwner = await User.findOne({ - where:{username} - }); - if(usernameOwner){ - message = 'username is'; - } - } catch(error) { - errorMessage = error.message; + }else if (username) { + try { + const usernameOwner = await User.findOne({ + where:{username} + }); + if (usernameOwner) { + message = 'username is'; } + } catch(error) { + errorMessage = error.message; } - if (message) { - return res.status(409).send({ - errors:{ - body:[`${message} already taken`] - } - }); - } if(errorMessage) { - return res.status(520).send({ - errors:{ - body:[ - errorMessage - ] - } - }); - } - } - try { - const profile = await User.findOne({ - attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, - where:{id}}); - profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); - let message; - if(user.email){ - await sendEmailConfirmationLink({ ...profile.get() }); - message = 'Your email is changed. Please check your email for confirmation' - }else { - message = 'The information was updated successful' - } - const{ confirmationCode, ...userData } = profile.get(); - return res.status(200).send({ - statu: 200, - message, - user: userData - }) - } catch(error) { + } + if (message) { + return res.status(409).send({ + errors:{ + body:[`${message} already taken`] + } + }); + } if (errorMessage) { return res.status(520).send({ errors:{ body:[ - error.message + errorMessage ] } - }) + }); + } + } + try { + const profile = await User.findOne({ + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, + where:{id}}); + profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); + let message; + if (user.email) { + await sendEmailConfirmationLink({ ...profile.get() }); + message = 'Your email is changed. Please check your email for confirmation' + } else { + message = 'The information was updated successful'; } + const{ confirmationCode, ...userData } = profile.get(); + return res.status(200).send({ + statu: 200, + message, + user: userData + }) + } catch(error) { + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) + } } } export default ProfileController; - diff --git a/middlewares/verifyJwt.js b/middlewares/verifyJwt.js index 78de5a6..c58324a 100644 --- a/middlewares/verifyJwt.js +++ b/middlewares/verifyJwt.js @@ -1,6 +1,6 @@ import passport from 'passport'; -const verifyJwt = (req,res,next) =>{ +const verifyJwt = (req,res,next) => { passport.authenticate('jwt', (err, user, info) => { if (err) { return res.status(520).send({errors: { body:[err.message] @@ -14,4 +14,4 @@ const verifyJwt = (req,res,next) =>{ })(req, res, next); } -export default verifyJwt; \ No newline at end of file +export default verifyJwt; diff --git a/package-lock.json b/package-lock.json index 4ed2080..2d996e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4946,9 +4946,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-api": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.0.tgz", - "integrity": "sha512-+Ygg4t1StoiNlBGc6x0f8q/Bv26FbZqP/+jegzfNpU7Q8o+4ZRoJxJPhBkgE/UonpAjtxnE4zCZIyJX+MwLRMQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", "dev": true, "requires": { "async": "^2.6.1", @@ -4959,7 +4959,7 @@ "istanbul-lib-instrument": "^3.1.0", "istanbul-lib-report": "^2.0.4", "istanbul-lib-source-maps": "^3.0.2", - "istanbul-reports": "^2.1.0", + "istanbul-reports": "^2.1.1", "js-yaml": "^3.12.0", "make-dir": "^1.3.0", "minimatch": "^3.0.4", @@ -5051,12 +5051,12 @@ } }, "istanbul-reports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.0.tgz", - "integrity": "sha512-azQdSX+dtTtkQEfqq20ICxWi6eOHXyHIgMFw1VOOVi8iIPWeCWRgCyFh/CsBKIhcgskMI8ExXmU7rjXTRCIJ+A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", "dev": true, "requires": { - "handlebars": "^4.0.11" + "handlebars": "^4.1.0" } }, "jest-changed-files": { diff --git a/routes/api/user.js b/routes/api/user.js index 6c668aa..f6934f9 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -12,4 +12,4 @@ router.put('/', verifyJwt, ProfileController.createProfile); -export default router; \ No newline at end of file +export default router; From 621a1ac2f30f9bafc917ac7f3527fb34f233379a Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 18:08:43 +0200 Subject: [PATCH 06/15] feat(profile) create profile -add new line -solved eslint errors --- __tests__/mocks/db.json | 3 +- __tests__/routes/profile.test.js | 342 ++++++++++++++++--------------- 2 files changed, 178 insertions(+), 167 deletions(-) diff --git a/__tests__/mocks/db.json b/__tests__/mocks/db.json index 6d52d51..550351d 100644 --- a/__tests__/mocks/db.json +++ b/__tests__/mocks/db.json @@ -26,4 +26,5 @@ "image": "https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg", "cover": "https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg" } -} \ No newline at end of file + +} diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index 18a73cb..e9d5cd7 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -9,180 +9,190 @@ const { JWT_SECRET } = process.env; let testUserToken; describe('Profile', () => { - beforeAll(async () => { - const { body } = await request(app) - .post(`${urlPrefix}/users`) - .send({ user: { - username: signupUser.username, - email: signupUser.email, - password: signupUser.password - } }); - testUserToken = body.user.token; + beforeAll(async () => { + const { body } = await request(app) + .post(`${urlPrefix}/users`) + .send({ user: { + username: signupUser.username, + email: signupUser.email, + password: signupUser.password + } }); + testUserToken = body.user.token; + }); + + afterAll(async () => { + await User.destroy({ + where: { email: signupUser.email } + }); + await User.destroy({ + where: { email: profile.email } + }) + }); + + test('should create profile and send confirmation when email is provided', async () => { + expect.assertions(11); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(200); + expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); + expect(res.body.user.firstName).toBe(profile.firstName); + expect(res.body.user.lastName).toBe(profile.lastName); + expect(res.body.user.username).toBe(profile.username); + expect(res.body.user.email).toBe(profile.email); + expect(res.body.user.bio).toBe(profile.bio); + expect(res.body.user.gender).toBe(profile.gender); + expect(res.body.user.birthDate).toBeDefined(); + expect(res.body.user.image).toBe(profile.image); + expect(res.body.user.cover).toBe(profile.cover); + }); + + test('should create profile and not send confirmation email when email is not provided', async () => { + expect.assertions(3); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + firstName: 'Peter' + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe('Peter'); + expect(res.body.message).toBe('The information was updated successful'); + }); + + test('should not create profile with --taken email and username', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email and username are already taken'); }); + + test('should not create profile with --taken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + email: profile.email + }}) - afterAll(async () => { + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + + test('should not create profile with --taken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + + test('should not create profile with --taken username and untaken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username, + email: 'papasava@email.com' + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + + test('should not create profile with --taken email and untaken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: 'papasava', + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + + test('should not create profile without --token', async () => { + expect.assertions(2); await User.destroy({ - where: { email: signupUser.email } + where: { email: 'john.doe@andela.com' } }); - await User.destroy({ - where: { email: profile.email } - }) + const res = await request(app) + .put(`${urlPrefix}/user`) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body[0]).toBe('No auth token'); }); - test('should create profile and send confirmation when email is provided', async () => { - expect.assertions(11); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(200); - expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); - expect(res.body.user.firstName).toBe(profile.firstName); - expect(res.body.user.lastName).toBe(profile.lastName); - expect(res.body.user.username).toBe(profile.username); - expect(res.body.user.email).toBe(profile.email); - expect(res.body.user.bio).toBe(profile.bio); - expect(res.body.user.gender).toBe(profile.gender); - expect(res.body.user.birthDate).toBeDefined(); - expect(res.body.user.image).toBe(profile.image); - expect(res.body.user.cover).toBe(profile.cover); - }); - test('should create profile and not send confirmation email when email is not provided', async () => { - expect.assertions(3); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - firstName: 'Peter' - }}) - - expect(res.status).toBe(200); - expect(res.body.user.firstName).toBe('Peter'); - expect(res.body.message).toBe('The information was updated successful'); - }); - test('should not create profile with --taken email and username', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email and username are already taken'); - }); - test('should not create profile with --taken email ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - email: profile.email - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email is already taken'); - }); - test('should not create profile with --taken username ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: profile.username - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('username is already taken'); - }); - test('should not create profile with --taken username and untaken email ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: profile.username, - email: 'papasava@email.com' - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('username is already taken'); - }); - test('should not create profile with --taken email and untaken username ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: 'papasava', - email: profile.email - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email is already taken'); - }); - test('should not create profile without --token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: 'john.doe@andela.com' } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(401); - expect(res.body.errors.body[0]).toBe('No auth token'); + test('should not create profile with --unexisting user', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}); - test('should not create profile with --unexisting user', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - expect(res.status).toBe(404); - expect(res.body.errors.body).toBeDefined(); - }); - test('should not create profile with --malformed token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', 'thgdihueh-jz') - .send({user: { - ...profile - }}) - - expect(res.status).toBe(401); - expect(res.body.errors.body).toBeDefined(); + expect(res.status).toBe(404); + expect(res.body.errors.body).toBeDefined(); + }); + + test('should not create profile with --malformed token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); - test('should not create profile with --incorrect token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', token) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(520); - expect(res.body.errors.body).toBeDefined(); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', 'thgdihueh-jz') + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body).toBeDefined(); + }); + + test('should not create profile with --incorrect token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); + const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', token) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(520); + expect(res.body.errors.body).toBeDefined(); + }); }); From 7bf2c00d29bd04f4f517202449954abc9fcdd82d Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Mon, 18 Feb 2019 12:14:33 +0200 Subject: [PATCH 07/15] feat(profile) create profile - add empty line --- controllers/ProfileController.js | 5 +++-- routes/validators/user.js | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 1815e0d..66c9bb8 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,6 +1,7 @@ import uuid from 'uuid'; import { User } from '../database/models'; import { sendEmailConfirmationLink } from './MailController'; + /** * @description ProfileContoller class */ @@ -9,7 +10,7 @@ class ProfileController { * @author Daniel * @param {*} req * @param {*} res - * @returns{*} user object + * @returns {*} user object */ static async createProfile(req, res) { const { user } = req.body; @@ -83,7 +84,7 @@ class ProfileController { let message; if (user.email) { await sendEmailConfirmationLink({ ...profile.get() }); - message = 'Your email is changed. Please check your email for confirmation' + message = 'Your email has changed. Please check your email for confirmation' } else { message = 'The information was updated successful'; } diff --git a/routes/validators/user.js b/routes/validators/user.js index dfcc247..335ee0f 100644 --- a/routes/validators/user.js +++ b/routes/validators/user.js @@ -21,4 +21,5 @@ const profile = { }) }; - export default profile; \ No newline at end of file + export default profile; + \ No newline at end of file From a19e82bd0d03d80f8c411486f387b9a0fceeaf45 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Tue, 12 Feb 2019 16:44:57 +0200 Subject: [PATCH 08/15] feat(profile) create profile -create route -add controller -add middleware --- .gitignore | 1 + app.js | 3 + controllers/ProfileController.js | 29 ++++ controllers/index.js | 5 +- .../migrations/20190205125059-create-user.js | 137 +++++++++--------- database/models/user.js | 7 +- middlewares/passportStrategies.js | 23 +-- package.json | 2 + routes/api/index.js | 3 +- routes/api/user.js | 28 ++++ 10 files changed, 160 insertions(+), 78 deletions(-) create mode 100644 controllers/ProfileController.js create mode 100644 routes/api/user.js diff --git a/.gitignore b/.gitignore index 251b921..c3411c4 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ shrinkwrap.yaml yarn.lock +package-lock.json # Winston logger files error.log diff --git a/app.js b/app.js index 19bd90d..b5ef59e 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,7 @@ import cors from 'cors'; import morgan from 'morgan'; import swaggerUI from 'swagger-ui-express'; import YAML from 'yamljs'; +import cookie from 'cookie-parser'; import methodOverride from 'method-override'; import { joiErrors } from './middlewares'; import routes from './routes'; @@ -14,6 +15,8 @@ const app = express(); const swaggerYAMLDocs = YAML.load('./docs/swagger.yml'); app.use(cors()); +app.use(cookie()); + app.use(morgan('dev')); app.use(express.urlencoded({ extended: false })); app.use(express.json()); diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js new file mode 100644 index 0000000..8ec4716 --- /dev/null +++ b/controllers/ProfileController.js @@ -0,0 +1,29 @@ +import { Op } from 'sequelize'; +import { User } from '../database/models'; + +/** + * @description ProfileContoller class + */ +class ProfileController { + /** + * @author Daniel + * @param {*} req + * @param {*} res + * @returns{*} profile object + */ + static async createProfile(req, res) { + const{ user } = req.body; + const { id } = req.body.currentUser; + const profile = await User.findOne({ + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt','updateAt']}, + where:{id}}); + console.log(profile); + profile.update(user); + return res.status(200).send({ + user: profile.get() + }) + } +} + +export default ProfileController; + diff --git a/controllers/index.js b/controllers/index.js index 5980c8a..9a45d31 100644 --- a/controllers/index.js +++ b/controllers/index.js @@ -1,5 +1,8 @@ import AuthController from './AuthController'; import UserController from './UserController'; import * as MailController from './MailController'; +import ProfileController from './ProfileController'; + +export { AuthController, UserController, MailController, ProfileController }; + -export { AuthController, UserController, MailController }; diff --git a/database/migrations/20190205125059-create-user.js b/database/migrations/20190205125059-create-user.js index 075768b..dbc02c2 100644 --- a/database/migrations/20190205125059-create-user.js +++ b/database/migrations/20190205125059-create-user.js @@ -1,68 +1,73 @@ -module.exports = { - up: (queryInterface, Sequelize) => - queryInterface.createTable('Users', { - id: { - type: Sequelize.UUID, - primaryKey: true, - defaultValue: Sequelize.UUIDV4 - }, - firstName: { - type: Sequelize.STRING - }, - lastName: { - type: Sequelize.STRING - }, - username: { - type: Sequelize.STRING, - allowNull: false, - unique: true - }, - email: { - type: Sequelize.STRING, - allowNull: false, - unique: true - }, - password: { - type: Sequelize.STRING, - allowNull: false - }, - bio: { - type: Sequelize.TEXT - }, - gender: { - type: Sequelize.STRING - }, - birthDate: { - type: Sequelize.DATE - }, - image: { - type: Sequelize.STRING - }, - cover: { - type: Sequelize.STRING - }, - status: { - type: Sequelize.STRING - }, - userType: { - type: Sequelize.STRING, - defaultValue: 'user' - }, - confirmationCode: { - type: Sequelize.STRING - }, - confirmed: { - type: Sequelize.STRING, - defaultValue: 'pending' - }, - createdAt: { - allowNull: false, - type: Sequelize.DATE - }, - updatedAt: { - allowNull: false, - type: Sequelize.DATE - } - }), +module.exports = { + up: (queryInterface, Sequelize) => + queryInterface.createTable('Users', { + id: { + type: Sequelize.UUID, + primaryKey: true, + defaultValue: Sequelize.UUIDV4 + }, + firstName: { + type: Sequelize.STRING + }, + lastName: { + type: Sequelize.STRING + }, + username: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true + }, + password: { + type: Sequelize.STRING, + allowNull: false + }, + bio: { + type: Sequelize.TEXT + }, + gender: { + type: Sequelize.STRING + }, + birthDate: { + type: Sequelize.DATE + }, + image: { + type: Sequelize.STRING + }, + cover: { + type: Sequelize.STRING + }, + status: { + type: Sequelize.STRING, + defaultValue: 'active' + }, + following: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + userType: { + type: Sequelize.STRING, + defaultValue: 'user' + }, + confirmationCode: { + type: Sequelize.STRING + }, + confirmed: { + type: Sequelize.STRING, + defaultValue: 'pending' + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }), down: (queryInterface, Sequelize) => queryInterface.dropTable('Users') }; diff --git a/database/models/user.js b/database/models/user.js index 711a80c..29512dd 100644 --- a/database/models/user.js +++ b/database/models/user.js @@ -43,7 +43,12 @@ module.exports = (sequelize, DataTypes) => { type: DataTypes.STRING }, status: { - type: DataTypes.STRING + type: DataTypes.STRING, + defaultValue: 'active' + }, + following: { + type: DataTypes.BOOLEAN, + defaultValue: false }, userType: { type: DataTypes.STRING, diff --git a/middlewares/passportStrategies.js b/middlewares/passportStrategies.js index 201e22b..322e92b 100644 --- a/middlewares/passportStrategies.js +++ b/middlewares/passportStrategies.js @@ -2,7 +2,7 @@ import bcrypt from 'bcrypt'; import passport from 'passport'; import { Op } from 'sequelize'; import { Strategy as LocalStrategy } from 'passport-local'; -import { Strategy as JWTStrategy } from 'passport-jwt'; +import { Strategy as JWTStrategy, ExtractJwt } from 'passport-jwt'; import 'dotenv/config'; import { User } from '../database/models'; @@ -35,22 +35,27 @@ passport.use( } ) ); - passport.use( 'jwt', new JWTStrategy( { - jwtFromRequest: req => req.cookies.jwt, + jwtFromRequest: ExtractJwt.fromHeader('authorization'), secretOrKey: JWT_SECRET }, - (jwtPayload, done) => { - if (Date.now() > jwtPayload.expires) { - return done('jwt expired'); + async (jwtPayload, done) => { + try { + const user = await User.findOne({ + where : {id: jwtPayload.id} + }); + if (!user) { + return done(null, false, { message: 'user does not exist' }); + } + return done(null, user.get()); + } catch(error) { + return done(error); } - - return done(null, jwtPayload); } ) -); +) export default passport; diff --git a/package.json b/package.json index 04380a4..0a85b9f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint:fix": "prettier-eslint --write '**/*.js'", "start": "npm run migrate:seed && babel-node index.js", "dev": "nodemon index.js --exec 'npm run lint && babel-node'", + "devstart": "nodemon index.js --exec babel-node", "migrate": "node_modules/.bin/sequelize db:migrate:undo:all && node_modules/.bin/sequelize db:migrate", "migrate:seed": "node_modules/.bin/sequelize db:migrate:undo:all && node_modules/.bin/sequelize db:migrate && node_modules/.bin/sequelize db:seed:all", "seed": "node_modules/.bin/sequelize db:seed:all" @@ -24,6 +25,7 @@ "babel-preset-airbnb": "^3.2.0", "bcrypt": "^3.0.3", "celebrate": "^9.0.2", + "cookie-parser": "^1.4.3", "cors": "^2.8.4", "coveralls": "^3.0.2", "dotenv": "^6.0.0", diff --git a/routes/api/index.js b/routes/api/index.js index f72dcd6..c070175 100644 --- a/routes/api/index.js +++ b/routes/api/index.js @@ -1,8 +1,9 @@ import express from 'express'; import users from './users'; +import user from './user'; const router = express.Router(); router.use('/users', users); - +router.use('/user', user); export default router; diff --git a/routes/api/user.js b/routes/api/user.js new file mode 100644 index 0000000..63d48db --- /dev/null +++ b/routes/api/user.js @@ -0,0 +1,28 @@ +import express from 'express'; +import passport from 'passport'; +import { ProfileController } from '../../controllers'; + + +const router = express.Router(); + +router.put('/', (req, res, next) => { + passport.authenticate('jwt', (err, user, info) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + if (!user) { const status = info.message === 'user does not exist'? 404:401; + return res.status(status).send({ errors: { + body: [info.message] + }}); } + req.logIn(user,{ session: false }, (err) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + req.body.currentUser = user; + return next(); + }); + })(req, res, next); + }, ProfileController.createProfile); + + +export default router; \ No newline at end of file From f7d5cfa26607450c6b23542f964756b8c525c40b Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Wed, 13 Feb 2019 19:25:48 +0200 Subject: [PATCH 09/15] feat(profile) create profile -add request body validation -add some test --- __tests__/routes/profile.test.js | 109 +++++++++++++++++++++++++++++++ controllers/AuthController.js | 7 ++ controllers/ProfileController.js | 20 ++++-- package-lock.json | 9 +++ routes/api/user.js | 8 ++- routes/validators/index.js | 3 +- routes/validators/user.js | 24 +++++++ 7 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 __tests__/routes/profile.test.js create mode 100644 routes/validators/user.js diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js new file mode 100644 index 0000000..a1027f6 --- /dev/null +++ b/__tests__/routes/profile.test.js @@ -0,0 +1,109 @@ +import request from 'supertest'; +import { User } from '../../database/models'; +import { signupUser } from '../mocks/db.json'; +import { urlPrefix } from '../mocks/variables.json'; +import app from '../../app'; + +let testUserToken; +describe('Profile', () => { + beforeAll(async () => { + const { body } = await request(app) + .post(`${urlPrefix}/users`) + .send({ user: { + username: signupUser.username, + email: signupUser.email, + password: signupUser.password + } }); + testUserToken = body.user.token; + }); + + afterAll(async () => { + await User.destroy({ + where: { email: signupUser.email } + }); + }); + + test('create profile', async () => { + expect.assertions(10); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe(profile.firstName); + expect(res.body.user.lastName).toBe(profile.lastName); + expect(res.body.user.username).toBe(profile.username); + expect(res.body.user.email).toBe(profile.email); + expect(res.body.user.bio).toBe(profile.bio); + expect(res.body.user.gender).toBe(profile.gender); + expect(res.body.user.birthDate).toBeDefined(); + expect(res.body.user.image).toBe(profile.image); + expect(res.body.user.cover).toBe(profile.cover); + }); + test('create profile without --token', async () => { + expect.assertions(1); + await User.destroy({ + where: { email: signupUser.email } + }); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + }); + + test('create profile with --unexisting user', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const profile = { + firstName: 'John', + lastName: 'Doe', + username: 'doe201', + email: 'john.doe@andela.com', + bio: 'I am software at Andela', + gender: 'Male', + birthDate: '12 June 1999', + image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', + cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' + } + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(404); + expect(res.body.errors.body).toBeDefined(); + }); + +}); \ No newline at end of file diff --git a/controllers/AuthController.js b/controllers/AuthController.js index 890c2d1..9433b67 100644 --- a/controllers/AuthController.js +++ b/controllers/AuthController.js @@ -42,6 +42,7 @@ class AuthController { return res.status(401).json({ status: 401, message: 'Please try again' }); } +<<<<<<< HEAD await sendEmailConfirmationLink({ ...userModel.get() }); const { password, confirmationCode, ...userData } = userModel.get(); @@ -49,6 +50,12 @@ class AuthController { return res.status(201).json({ status: 201, message: 'Account created sucessfully. Please check your email for confirmation', +======= + const { password, ...userData } = userModel.get(); + return res.status(201).json({ + status: 201, + message: 'Account created sucessfully', +>>>>>>> feat(profile) create profile user: { ...userData, token } }); } diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 8ec4716..f442b95 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,4 +1,3 @@ -import { Op } from 'sequelize'; import { User } from '../database/models'; /** @@ -9,19 +8,28 @@ class ProfileController { * @author Daniel * @param {*} req * @param {*} res - * @returns{*} profile object + * @returns{*} user object */ static async createProfile(req, res) { const{ user } = req.body; - const { id } = req.body.currentUser; + const { id } = req.currentUser; + try { const profile = await User.findOne({ - attributes:{ exclude: ['password', 'status', 'following','userType','createdAt','updateAt']}, + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); - console.log(profile); - profile.update(user); + profile.update({updateAt: new Date(),...user}); return res.status(200).send({ user: profile.get() }) + } catch(error) { + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) + } } } diff --git a/package-lock.json b/package-lock.json index 2ea659b..85c528d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2432,6 +2432,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, + "cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", diff --git a/routes/api/user.js b/routes/api/user.js index 63d48db..3adca5e 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -1,6 +1,8 @@ import express from 'express'; import passport from 'passport'; +import { celebrate } from 'celebrate'; import { ProfileController } from '../../controllers'; +import { profileValidator } from '../validators' const router = express.Router(); @@ -18,11 +20,13 @@ router.put('/', (req, res, next) => { if (err) { return res.status(520).send({errors: { body:[err.message] }}); } - req.body.currentUser = user; + req.currentUser = user; return next(); }); })(req, res, next); - }, ProfileController.createProfile); + }, + celebrate({ body: profileValidator }), + ProfileController.createProfile); export default router; \ No newline at end of file diff --git a/routes/validators/index.js b/routes/validators/index.js index 6835db6..1bb2e27 100644 --- a/routes/validators/index.js +++ b/routes/validators/index.js @@ -1,3 +1,4 @@ import authValidator from './auth'; +import profileValidator from './user'; -export { authValidator }; +export { authValidator, profileValidator}; diff --git a/routes/validators/user.js b/routes/validators/user.js new file mode 100644 index 0000000..dfcc247 --- /dev/null +++ b/routes/validators/user.js @@ -0,0 +1,24 @@ +import { Joi } from 'celebrate'; + +const profile = { + user: Joi.object().keys({ + username: Joi.string() + .trim(), + firstName: Joi.string() + .min(3), + lastName: Joi.string() + .min(3), + email: Joi.string() + .email() + .trim(), + bio: Joi.string() + .min(20), + gender: Joi.string() + .max(6), + birthDate: Joi.date(), + image: Joi.string(), + cover: Joi.string(), + }) + }; + + export default profile; \ No newline at end of file From d89be6882244af5a908154ea6fc8c821241c1ec3 Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 13:50:34 +0200 Subject: [PATCH 10/15] feat(profile) create profile - add more test - enable user to use taken username and email --- __tests__/mocks/db.json | 13 +- __tests__/routes/profile.test.js | 147 +++++++--- controllers/AuthController.js | 7 - controllers/ProfileController.js | 89 +++++- package-lock.json | 472 +++++++++++-------------------- routes/api/user.js | 5 - 6 files changed, 352 insertions(+), 381 deletions(-) diff --git a/__tests__/mocks/db.json b/__tests__/mocks/db.json index 08cf944..6d52d51 100644 --- a/__tests__/mocks/db.json +++ b/__tests__/mocks/db.json @@ -14,5 +14,16 @@ "id": "578c8188-cba6-45f6-842f-8d80c247b818", "username": "oemapp", "email": "oemapp.dev@gmail.com" + }, + "profile":{ + "firstName": "John", + "lastName": "Doe", + "username": "doe201", + "email": "john.doe@andela.com", + "bio": "I am software at Andela", + "gender": "Male", + "birthDate": "12 June 1999", + "image": "https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg", + "cover": "https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg" } -} +} \ No newline at end of file diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index a1027f6..8c74553 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -1,9 +1,12 @@ import request from 'supertest'; +import jwt from 'jsonwebtoken'; import { User } from '../../database/models'; -import { signupUser } from '../mocks/db.json'; +import { signupUser, profile } from '../mocks/db.json'; import { urlPrefix } from '../mocks/variables.json'; import app from '../../app'; +const { JWT_SECRET } = process.env; + let testUserToken; describe('Profile', () => { beforeAll(async () => { @@ -21,21 +24,13 @@ describe('Profile', () => { await User.destroy({ where: { email: signupUser.email } }); + await User.destroy({ + where: { email: profile.email } + }) }); - test('create profile', async () => { + test('should create profile', async () => { expect.assertions(10); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) @@ -54,22 +49,73 @@ describe('Profile', () => { expect(res.body.user.image).toBe(profile.image); expect(res.body.user.cover).toBe(profile.cover); }); - test('create profile without --token', async () => { - expect.assertions(1); + test('should not create profile with --taken email and username', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email and username are already taken'); + }); + test('should not create profile with --taken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + test('should not create profile with --taken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + test('should not create profile with --taken username and untaken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username, + email: 'papasava@email.com' + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + test('should not create profile with --taken email and untaken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: 'papasava', + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + test('should not create profile without --token', async () => { + expect.assertions(2); await User.destroy({ - where: { email: signupUser.email } + where: { email: 'john.doe@andela.com' } }); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .send({user: { @@ -77,33 +123,52 @@ describe('Profile', () => { }}) expect(res.status).toBe(401); + expect(res.body.errors.body[0]).toBe('No auth token'); }); - test('create profile with --unexisting user', async () => { + test('should not create profile with --unexisting user', async () => { expect.assertions(2); await User.destroy({ where: { email: signupUser.email } }); - const profile = { - firstName: 'John', - lastName: 'Doe', - username: 'doe201', - email: 'john.doe@andela.com', - bio: 'I am software at Andela', - gender: 'Male', - birthDate: '12 June 1999', - image: 'https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg', - cover: 'https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg' - } const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) .send({user: { ...profile }}) - expect(res.status).toBe(404); expect(res.body.errors.body).toBeDefined(); }); - + test('should not create profile with --malformed token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', 'thgdihueh-jz') + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body).toBeDefined(); + }); + test('should not create profile with --incorrect token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } + }); + const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', token) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(520); + expect(res.body.errors.body).toBeDefined(); + }); }); \ No newline at end of file diff --git a/controllers/AuthController.js b/controllers/AuthController.js index 9433b67..890c2d1 100644 --- a/controllers/AuthController.js +++ b/controllers/AuthController.js @@ -42,7 +42,6 @@ class AuthController { return res.status(401).json({ status: 401, message: 'Please try again' }); } -<<<<<<< HEAD await sendEmailConfirmationLink({ ...userModel.get() }); const { password, confirmationCode, ...userData } = userModel.get(); @@ -50,12 +49,6 @@ class AuthController { return res.status(201).json({ status: 201, message: 'Account created sucessfully. Please check your email for confirmation', -======= - const { password, ...userData } = userModel.get(); - return res.status(201).json({ - status: 201, - message: 'Account created sucessfully', ->>>>>>> feat(profile) create profile user: { ...userData, token } }); } diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index f442b95..23709a1 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -4,31 +4,92 @@ import { User } from '../database/models'; * @description ProfileContoller class */ class ProfileController { - /** - * @author Daniel - * @param {*} req - * @param {*} res - * @returns{*} user object - */ + /** + * @author Daniel + * @param {*} req + * @param {*} res + * @returns{*} user object + */ static async createProfile(req, res) { const{ user } = req.body; const { id } = req.currentUser; + const{ email, username } = req.body.user; + if (email || username) { + let message; + let errorMessage; + if (email && username ){ + try { + const emailOwner = await User.findOne({ + where:{email} + }) + const usernameOwner = await User.findOne({ + where:{username} + }) + if(emailOwner && usernameOwner){ + message = 'email and username are'; + } else if(emailOwner){ + message = 'email is'; + } else if(usernameOwner){ + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } else if(email) { + try { + const emailOwner = await User.findOne({ + where:{email} + }); + if(emailOwner){ + message = 'email is'; + } + } catch(error) { + errorMessage = error.message; + } + }else if(username){ + try { + const usernameOwner = await User.findOne({ + where:{username} + }); + if(usernameOwner){ + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } + if (message) { + return res.status(409).send({ + errors:{ + body:[`${message} already taken`] + } + }); + } if(errorMessage) { + return res.status(520).send({ + errors:{ + body:[ + errorMessage + ] + } + }); + } + } try { const profile = await User.findOne({ attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); profile.update({updateAt: new Date(),...user}); return res.status(200).send({ - user: profile.get() + user: profile.get() }) } catch(error) { - return res.status(520).send({ - errors:{ - body:[ - error.message - ] - } - }) + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) } } } diff --git a/package-lock.json b/package-lock.json index 85c528d..4ed2080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -838,9 +838,9 @@ "integrity": "sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==" }, "@types/node": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.0.tgz", - "integrity": "sha512-ry4DOrC+xenhQbzk1iIPzCZGhhPGEFv7ia7Iu6XXSLVluiJIe9FfG7Iu3mObH9mpxEXCWLCMU4JWbCCR9Oy1Zg==" + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.3.tgz", + "integrity": "sha512-DMiqG51GwES/c4ScBY0u5bDlH44+oY8AeYHjY1SGCWidD7h08o1dfHue/TGK7REmif2KiJzaUskO+Q0eaeZ2fQ==" }, "@types/request": { "version": "2.48.1", @@ -1364,23 +1364,19 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "bundled": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "bundled": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "bundled": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "bundled": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -1388,13 +1384,11 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "bundled": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1402,69 +1396,57 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + "bundled": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "bundled": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "bundled": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "bundled": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, "requires": { "ms": "2.0.0" } }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "bundled": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "bundled": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + "bundled": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "requires": { "minipass": "^2.2.1" } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "bundled": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -1478,8 +1460,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "bundled": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1491,29 +1472,25 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "bundled": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "bundled": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "requires": { "minimatch": "^3.0.4" } }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1521,44 +1498,37 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "bundled": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "bundled": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "bundled": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "bundled": true }, "minipass": { "version": "2.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz", - "integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==", + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1566,41 +1536,35 @@ "dependencies": { "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + "bundled": true } } }, "minizlib": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz", - "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==", + "bundled": true, "requires": { "minipass": "^2.2.1" } }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "bundled": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "bundled": true, "requires": { "debug": "^2.1.2", "iconv-lite": "^0.4.4", @@ -1609,8 +1573,7 @@ }, "node-pre-gyp": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", - "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "bundled": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -1626,8 +1589,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -1635,13 +1597,11 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==" + "bundled": true }, "npm-packlist": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz", - "integrity": "sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==", + "bundled": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -1649,8 +1609,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -1660,36 +1619,30 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "bundled": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "bundled": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "bundled": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -1697,18 +1650,15 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "bundled": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "bundled": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -1718,15 +1668,13 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "bundled": true } } }, "readable-stream": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", - "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "bundled": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1739,46 +1687,38 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "bundled": true, "requires": { "glob": "^7.0.5" } }, "safe-buffer": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "bundled": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "bundled": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "bundled": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "bundled": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "bundled": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1787,29 +1727,25 @@ }, "string_decoder": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "bundled": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "bundled": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "bundled": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -1822,33 +1758,28 @@ "dependencies": { "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bundled": true }, "yallist": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + "bundled": true } } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "bundled": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "bundled": true, "requires": { "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "bundled": true } } }, @@ -2433,9 +2364,9 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, "cookie-parser": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", - "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", + "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", "requires": { "cookie": "0.3.1", "cookie-signature": "1.0.6" @@ -2778,9 +2709,9 @@ }, "dependencies": { "@types/node": { - "version": "10.12.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.25.tgz", - "integrity": "sha512-IcvnGLGSQFDvC07Bz2I8SX+QKErDZbUdiQq7S2u3XyzTyJfUmT0sWJMbeQkMzpTAkO7/N7sZpW/arUM2jfKsbQ==" + "version": "10.12.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.26.tgz", + "integrity": "sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg==" } } }, @@ -3811,26 +3742,21 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "bundled": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "bundled": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -3839,15 +3765,11 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, + "bundled": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3855,38 +3777,29 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "bundled": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "bundled": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "bundled": true, "optional": true, "requires": { "ms": "2.0.0" @@ -3894,26 +3807,22 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "bundled": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "bundled": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bundled": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -3921,14 +3830,12 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -3943,8 +3850,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "bundled": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -3957,14 +3863,12 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "bundled": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "bundled": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -3972,8 +3876,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -3981,8 +3884,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "optional": true, "requires": { "once": "^1.3.0", @@ -3991,51 +3893,39 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "bundled": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, + "bundled": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, + "bundled": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "optional": true, + "bundled": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4043,8 +3933,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "bundled": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -4052,23 +3941,19 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, + "bundled": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "bundled": true, "optional": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "bundled": true, "optional": true, "requires": { "debug": "^2.1.2", @@ -4078,8 +3963,7 @@ }, "node-pre-gyp": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", - "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", + "bundled": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -4096,8 +3980,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "optional": true, "requires": { "abbrev": "1", @@ -4106,14 +3989,12 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", + "bundled": true, "optional": true }, "npm-packlist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz", - "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", + "bundled": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -4122,8 +4003,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -4134,41 +4014,33 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, + "bundled": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "bundled": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -4177,20 +4049,17 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "bundled": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "bundled": true, "optional": true, "requires": { "deep-extend": "^0.6.0", @@ -4201,16 +4070,14 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "bundled": true, "optional": true } } }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -4224,8 +4091,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "bundled": true, "optional": true, "requires": { "glob": "^7.1.3" @@ -4233,45 +4099,36 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "bundled": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "bundled": true, "optional": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "bundled": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, + "bundled": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4280,8 +4137,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -4289,23 +4145,19 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, + "bundled": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bundled": true, "optional": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "bundled": true, "optional": true, "requires": { "chownr": "^1.1.1", @@ -4319,14 +4171,12 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "bundled": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "bundled": true, "optional": true, "requires": { "string-width": "^1.0.2 || 2" @@ -4334,15 +4184,11 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "optional": true + "bundled": true } } }, @@ -4494,12 +4340,12 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "source-map": { @@ -5121,12 +4967,12 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } } } @@ -7978,9 +7824,9 @@ } }, "realpath-native": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", - "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", "dev": true, "requires": { "util.promisify": "^1.0.0" @@ -9742,11 +9588,11 @@ }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "readable-stream": { diff --git a/routes/api/user.js b/routes/api/user.js index 3adca5e..4f4945c 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -16,13 +16,8 @@ router.put('/', (req, res, next) => { return res.status(status).send({ errors: { body: [info.message] }}); } - req.logIn(user,{ session: false }, (err) => { - if (err) { return res.status(520).send({errors: { - body:[err.message] - }}); } req.currentUser = user; return next(); - }); })(req, res, next); }, celebrate({ body: profileValidator }), From 295f52aed6ef60ad860d6367bfdc9c405416c75e Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 16:02:56 +0200 Subject: [PATCH 11/15] feat(profile) create profile - add confirmation when user change email - add test ' --- __tests__/routes/profile.test.js | 18 ++++++++++++++++-- controllers/ProfileController.js | 17 ++++++++++++++--- middlewares/index.js | 3 ++- middlewares/verifyJwt.js | 17 +++++++++++++++++ package.json | 1 + routes/api/user.js | 18 +++--------------- 6 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 middlewares/verifyJwt.js diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index 8c74553..da309ef 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -29,8 +29,8 @@ describe('Profile', () => { }) }); - test('should create profile', async () => { - expect.assertions(10); + test('should create profile and send confirmation when email is provided', async () => { + expect.assertions(11); const res = await request(app) .put(`${urlPrefix}/user`) .set('Authorization', testUserToken) @@ -39,6 +39,7 @@ describe('Profile', () => { }}) expect(res.status).toBe(200); + expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); expect(res.body.user.firstName).toBe(profile.firstName); expect(res.body.user.lastName).toBe(profile.lastName); expect(res.body.user.username).toBe(profile.username); @@ -49,6 +50,19 @@ describe('Profile', () => { expect(res.body.user.image).toBe(profile.image); expect(res.body.user.cover).toBe(profile.cover); }); + test('should create profile and not send confirmation email when email is not provided', async () => { + expect.assertions(3); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + firstName: 'Peter' + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe('Peter'); + expect(res.body.message).toBe('The information was updated successful'); + }); test('should not create profile with --taken email and username', async () => { expect.assertions(2); const res = await request(app) diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 23709a1..3f98b99 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,5 +1,6 @@ +import uuid from 'uuid'; import { User } from '../database/models'; - +import { sendEmailConfirmationLink } from './MailController'; /** * @description ProfileContoller class */ @@ -78,9 +79,19 @@ class ProfileController { const profile = await User.findOne({ attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, where:{id}}); - profile.update({updateAt: new Date(),...user}); + profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); + let message; + if(user.email){ + await sendEmailConfirmationLink({ ...profile.get() }); + message = 'Your email is changed. Please check your email for confirmation' + }else { + message = 'The information was updated successful' + } + const{ confirmationCode, ...userData } = profile.get(); return res.status(200).send({ - user: profile.get() + statu: 200, + message, + user: userData }) } catch(error) { return res.status(520).send({ diff --git a/middlewares/index.js b/middlewares/index.js index cc0df35..f52c554 100644 --- a/middlewares/index.js +++ b/middlewares/index.js @@ -1,4 +1,5 @@ import joiErrors from './joiErrors'; import passportStrategies from './passportStrategies'; +import verifyJwt from './verifyJwt'; -export { joiErrors, passportStrategies }; +export { joiErrors, passportStrategies, verifyJwt }; diff --git a/middlewares/verifyJwt.js b/middlewares/verifyJwt.js new file mode 100644 index 0000000..78de5a6 --- /dev/null +++ b/middlewares/verifyJwt.js @@ -0,0 +1,17 @@ +import passport from 'passport'; + +const verifyJwt = (req,res,next) =>{ + passport.authenticate('jwt', (err, user, info) => { + if (err) { return res.status(520).send({errors: { + body:[err.message] + }}); } + if (!user) { const status = info.message === 'user does not exist'? 404:401; + return res.status(status).send({ errors: { + body: [info.message] + }}); } + req.currentUser = user; + return next(); + })(req, res, next); +} + +export default verifyJwt; \ No newline at end of file diff --git a/package.json b/package.json index 0a85b9f..ba3f5a0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "slug": "^0.9.3", "swagger-ui-express": "^4.0.2", "underscore": "^1.9.1", + "uuid": "^3.3.2", "winston": "^3.2.1", "yamljs": "^0.3.0" }, diff --git a/routes/api/user.js b/routes/api/user.js index 4f4945c..6c668aa 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -1,25 +1,13 @@ import express from 'express'; -import passport from 'passport'; import { celebrate } from 'celebrate'; import { ProfileController } from '../../controllers'; -import { profileValidator } from '../validators' +import { profileValidator } from '../validators'; +import { verifyJwt } from '../../middlewares'; const router = express.Router(); -router.put('/', (req, res, next) => { - passport.authenticate('jwt', (err, user, info) => { - if (err) { return res.status(520).send({errors: { - body:[err.message] - }}); } - if (!user) { const status = info.message === 'user does not exist'? 404:401; - return res.status(status).send({ errors: { - body: [info.message] - }}); } - req.currentUser = user; - return next(); - })(req, res, next); - }, +router.put('/', verifyJwt, celebrate({ body: profileValidator }), ProfileController.createProfile); From ecf71aac8261fa75becb4347d04d7a152d2e3a6b Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 17:49:02 +0200 Subject: [PATCH 12/15] feat(profile) create profile -add new line -solved eslint errors --- __tests__/routes/profile.test.js | 2 +- controllers/ProfileController.js | 149 +++++++++++++++---------------- middlewares/verifyJwt.js | 4 +- package-lock.json | 16 ++-- routes/api/user.js | 2 +- 5 files changed, 86 insertions(+), 87 deletions(-) diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index da309ef..18a73cb 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -185,4 +185,4 @@ describe('Profile', () => { expect(res.status).toBe(520); expect(res.body.errors.body).toBeDefined(); }); -}); \ No newline at end of file +}); diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 3f98b99..1815e0d 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -12,98 +12,97 @@ class ProfileController { * @returns{*} user object */ static async createProfile(req, res) { - const{ user } = req.body; - const { id } = req.currentUser; - const{ email, username } = req.body.user; - if (email || username) { - let message; - let errorMessage; - if (email && username ){ + const { user } = req.body; + const { id } = req.currentUser; + const { email, username } = req.body.user; + if (email || username) { + let message; + let errorMessage; + if (email && username ) { + try { + const emailOwner = await User.findOne({ + where:{email} + }) + const usernameOwner = await User.findOne({ + where:{username} + }) + if (emailOwner && usernameOwner) { + message = 'email and username are'; + } else if (emailOwner) { + message = 'email is'; + } else if (usernameOwner) { + message = 'username is'; + } + } catch(error) { + errorMessage = error.message; + } + } else if (email) { try { const emailOwner = await User.findOne({ where:{email} - }) - const usernameOwner = await User.findOne({ - where:{username} - }) - if(emailOwner && usernameOwner){ - message = 'email and username are'; - } else if(emailOwner){ + }); + if(emailOwner){ message = 'email is'; - } else if(usernameOwner){ - message = 'username is'; } } catch(error) { errorMessage = error.message; } - } else if(email) { - try { - const emailOwner = await User.findOne({ - where:{email} - }); - if(emailOwner){ - message = 'email is'; - } - } catch(error) { - errorMessage = error.message; - } - }else if(username){ - try { - const usernameOwner = await User.findOne({ - where:{username} - }); - if(usernameOwner){ - message = 'username is'; - } - } catch(error) { - errorMessage = error.message; + }else if (username) { + try { + const usernameOwner = await User.findOne({ + where:{username} + }); + if (usernameOwner) { + message = 'username is'; } + } catch(error) { + errorMessage = error.message; } - if (message) { - return res.status(409).send({ - errors:{ - body:[`${message} already taken`] - } - }); - } if(errorMessage) { - return res.status(520).send({ - errors:{ - body:[ - errorMessage - ] - } - }); - } - } - try { - const profile = await User.findOne({ - attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, - where:{id}}); - profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); - let message; - if(user.email){ - await sendEmailConfirmationLink({ ...profile.get() }); - message = 'Your email is changed. Please check your email for confirmation' - }else { - message = 'The information was updated successful' - } - const{ confirmationCode, ...userData } = profile.get(); - return res.status(200).send({ - statu: 200, - message, - user: userData - }) - } catch(error) { + } + if (message) { + return res.status(409).send({ + errors:{ + body:[`${message} already taken`] + } + }); + } if (errorMessage) { return res.status(520).send({ errors:{ body:[ - error.message + errorMessage ] } - }) + }); + } + } + try { + const profile = await User.findOne({ + attributes:{ exclude: ['password', 'status', 'following','userType','createdAt']}, + where:{id}}); + profile.update({updateAt: new Date(),...user, confirmationCode: uuid.v4(), confirmed: 'pending'}); + let message; + if (user.email) { + await sendEmailConfirmationLink({ ...profile.get() }); + message = 'Your email is changed. Please check your email for confirmation' + } else { + message = 'The information was updated successful'; } + const{ confirmationCode, ...userData } = profile.get(); + return res.status(200).send({ + statu: 200, + message, + user: userData + }) + } catch(error) { + return res.status(520).send({ + errors:{ + body:[ + error.message + ] + } + }) + } } } export default ProfileController; - diff --git a/middlewares/verifyJwt.js b/middlewares/verifyJwt.js index 78de5a6..c58324a 100644 --- a/middlewares/verifyJwt.js +++ b/middlewares/verifyJwt.js @@ -1,6 +1,6 @@ import passport from 'passport'; -const verifyJwt = (req,res,next) =>{ +const verifyJwt = (req,res,next) => { passport.authenticate('jwt', (err, user, info) => { if (err) { return res.status(520).send({errors: { body:[err.message] @@ -14,4 +14,4 @@ const verifyJwt = (req,res,next) =>{ })(req, res, next); } -export default verifyJwt; \ No newline at end of file +export default verifyJwt; diff --git a/package-lock.json b/package-lock.json index 4ed2080..2d996e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4946,9 +4946,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-api": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.0.tgz", - "integrity": "sha512-+Ygg4t1StoiNlBGc6x0f8q/Bv26FbZqP/+jegzfNpU7Q8o+4ZRoJxJPhBkgE/UonpAjtxnE4zCZIyJX+MwLRMQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", "dev": true, "requires": { "async": "^2.6.1", @@ -4959,7 +4959,7 @@ "istanbul-lib-instrument": "^3.1.0", "istanbul-lib-report": "^2.0.4", "istanbul-lib-source-maps": "^3.0.2", - "istanbul-reports": "^2.1.0", + "istanbul-reports": "^2.1.1", "js-yaml": "^3.12.0", "make-dir": "^1.3.0", "minimatch": "^3.0.4", @@ -5051,12 +5051,12 @@ } }, "istanbul-reports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.0.tgz", - "integrity": "sha512-azQdSX+dtTtkQEfqq20ICxWi6eOHXyHIgMFw1VOOVi8iIPWeCWRgCyFh/CsBKIhcgskMI8ExXmU7rjXTRCIJ+A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", "dev": true, "requires": { - "handlebars": "^4.0.11" + "handlebars": "^4.1.0" } }, "jest-changed-files": { diff --git a/routes/api/user.js b/routes/api/user.js index 6c668aa..f6934f9 100644 --- a/routes/api/user.js +++ b/routes/api/user.js @@ -12,4 +12,4 @@ router.put('/', verifyJwt, ProfileController.createProfile); -export default router; \ No newline at end of file +export default router; From 5c9b3d032f2cf42872b33baea76479d5e190d72b Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Thu, 14 Feb 2019 18:08:43 +0200 Subject: [PATCH 13/15] feat(profile) create profile -add new line -solved eslint errors --- __tests__/mocks/db.json | 3 +- __tests__/routes/profile.test.js | 342 ++++++++++++++++--------------- 2 files changed, 178 insertions(+), 167 deletions(-) diff --git a/__tests__/mocks/db.json b/__tests__/mocks/db.json index 6d52d51..550351d 100644 --- a/__tests__/mocks/db.json +++ b/__tests__/mocks/db.json @@ -26,4 +26,5 @@ "image": "https://planetbotanix.com/wp-content/uploads/2017/08/Female-Avatar-1-300x300.jpg", "cover": "https://www.eta.co.uk/wp-content/uploads/2012/09/Cycling-by-water-resized-min.jpg" } -} \ No newline at end of file + +} diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index 18a73cb..e9d5cd7 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -9,180 +9,190 @@ const { JWT_SECRET } = process.env; let testUserToken; describe('Profile', () => { - beforeAll(async () => { - const { body } = await request(app) - .post(`${urlPrefix}/users`) - .send({ user: { - username: signupUser.username, - email: signupUser.email, - password: signupUser.password - } }); - testUserToken = body.user.token; + beforeAll(async () => { + const { body } = await request(app) + .post(`${urlPrefix}/users`) + .send({ user: { + username: signupUser.username, + email: signupUser.email, + password: signupUser.password + } }); + testUserToken = body.user.token; + }); + + afterAll(async () => { + await User.destroy({ + where: { email: signupUser.email } + }); + await User.destroy({ + where: { email: profile.email } + }) + }); + + test('should create profile and send confirmation when email is provided', async () => { + expect.assertions(11); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(200); + expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); + expect(res.body.user.firstName).toBe(profile.firstName); + expect(res.body.user.lastName).toBe(profile.lastName); + expect(res.body.user.username).toBe(profile.username); + expect(res.body.user.email).toBe(profile.email); + expect(res.body.user.bio).toBe(profile.bio); + expect(res.body.user.gender).toBe(profile.gender); + expect(res.body.user.birthDate).toBeDefined(); + expect(res.body.user.image).toBe(profile.image); + expect(res.body.user.cover).toBe(profile.cover); + }); + + test('should create profile and not send confirmation email when email is not provided', async () => { + expect.assertions(3); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + firstName: 'Peter' + }}) + + expect(res.status).toBe(200); + expect(res.body.user.firstName).toBe('Peter'); + expect(res.body.message).toBe('The information was updated successful'); + }); + + test('should not create profile with --taken email and username', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email and username are already taken'); }); + + test('should not create profile with --taken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + email: profile.email + }}) - afterAll(async () => { + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + + test('should not create profile with --taken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + + test('should not create profile with --taken username and untaken email ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: profile.username, + email: 'papasava@email.com' + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('username is already taken'); + }); + + test('should not create profile with --taken email and untaken username ', async () => { + expect.assertions(2); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + username: 'papasava', + email: profile.email + }}) + + expect(res.status).toBe(409); + expect(res.body.errors.body[0]).toBe('email is already taken'); + }); + + test('should not create profile without --token', async () => { + expect.assertions(2); await User.destroy({ - where: { email: signupUser.email } + where: { email: 'john.doe@andela.com' } }); - await User.destroy({ - where: { email: profile.email } - }) + const res = await request(app) + .put(`${urlPrefix}/user`) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body[0]).toBe('No auth token'); }); - test('should create profile and send confirmation when email is provided', async () => { - expect.assertions(11); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(200); - expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); - expect(res.body.user.firstName).toBe(profile.firstName); - expect(res.body.user.lastName).toBe(profile.lastName); - expect(res.body.user.username).toBe(profile.username); - expect(res.body.user.email).toBe(profile.email); - expect(res.body.user.bio).toBe(profile.bio); - expect(res.body.user.gender).toBe(profile.gender); - expect(res.body.user.birthDate).toBeDefined(); - expect(res.body.user.image).toBe(profile.image); - expect(res.body.user.cover).toBe(profile.cover); - }); - test('should create profile and not send confirmation email when email is not provided', async () => { - expect.assertions(3); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - firstName: 'Peter' - }}) - - expect(res.status).toBe(200); - expect(res.body.user.firstName).toBe('Peter'); - expect(res.body.message).toBe('The information was updated successful'); - }); - test('should not create profile with --taken email and username', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email and username are already taken'); - }); - test('should not create profile with --taken email ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - email: profile.email - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email is already taken'); - }); - test('should not create profile with --taken username ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: profile.username - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('username is already taken'); - }); - test('should not create profile with --taken username and untaken email ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: profile.username, - email: 'papasava@email.com' - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('username is already taken'); - }); - test('should not create profile with --taken email and untaken username ', async () => { - expect.assertions(2); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - username: 'papasava', - email: profile.email - }}) - - expect(res.status).toBe(409); - expect(res.body.errors.body[0]).toBe('email is already taken'); - }); - test('should not create profile without --token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: 'john.doe@andela.com' } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(401); - expect(res.body.errors.body[0]).toBe('No auth token'); + test('should not create profile with --unexisting user', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', testUserToken) + .send({user: { + ...profile + }}); - test('should not create profile with --unexisting user', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', testUserToken) - .send({user: { - ...profile - }}) - expect(res.status).toBe(404); - expect(res.body.errors.body).toBeDefined(); - }); - test('should not create profile with --malformed token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', 'thgdihueh-jz') - .send({user: { - ...profile - }}) - - expect(res.status).toBe(401); - expect(res.body.errors.body).toBeDefined(); + expect(res.status).toBe(404); + expect(res.body.errors.body).toBeDefined(); + }); + + test('should not create profile with --malformed token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); - test('should not create profile with --incorrect token', async () => { - expect.assertions(2); - await User.destroy({ - where: { email: signupUser.email } - }); - const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); - const res = await request(app) - .put(`${urlPrefix}/user`) - .set('Authorization', token) - .send({user: { - ...profile - }}) - - expect(res.status).toBe(520); - expect(res.body.errors.body).toBeDefined(); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', 'thgdihueh-jz') + .send({user: { + ...profile + }}) + + expect(res.status).toBe(401); + expect(res.body.errors.body).toBeDefined(); + }); + + test('should not create profile with --incorrect token', async () => { + expect.assertions(2); + await User.destroy({ + where: { email: signupUser.email } }); + const token = jwt.sign({ id: 12345, userType: 'user' }, JWT_SECRET); + const res = await request(app) + .put(`${urlPrefix}/user`) + .set('Authorization', token) + .send({user: { + ...profile + }}) + + expect(res.status).toBe(520); + expect(res.body.errors.body).toBeDefined(); + }); }); From 3f30ca69a98ae1c5768bdd21fc0cc36f286698ef Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Mon, 18 Feb 2019 12:14:33 +0200 Subject: [PATCH 14/15] feat(profile) create profile - add empty line --- controllers/ProfileController.js | 5 +++-- routes/validators/user.js | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/controllers/ProfileController.js b/controllers/ProfileController.js index 1815e0d..66c9bb8 100644 --- a/controllers/ProfileController.js +++ b/controllers/ProfileController.js @@ -1,6 +1,7 @@ import uuid from 'uuid'; import { User } from '../database/models'; import { sendEmailConfirmationLink } from './MailController'; + /** * @description ProfileContoller class */ @@ -9,7 +10,7 @@ class ProfileController { * @author Daniel * @param {*} req * @param {*} res - * @returns{*} user object + * @returns {*} user object */ static async createProfile(req, res) { const { user } = req.body; @@ -83,7 +84,7 @@ class ProfileController { let message; if (user.email) { await sendEmailConfirmationLink({ ...profile.get() }); - message = 'Your email is changed. Please check your email for confirmation' + message = 'Your email has changed. Please check your email for confirmation' } else { message = 'The information was updated successful'; } diff --git a/routes/validators/user.js b/routes/validators/user.js index dfcc247..335ee0f 100644 --- a/routes/validators/user.js +++ b/routes/validators/user.js @@ -21,4 +21,5 @@ const profile = { }) }; - export default profile; \ No newline at end of file + export default profile; + \ No newline at end of file From 387a94873384319112f1a2ef40344567829a59bb Mon Sep 17 00:00:00 2001 From: Nziranziza Date: Mon, 18 Feb 2019 12:22:42 +0200 Subject: [PATCH 15/15] feat(profile) create profile add more test --- __tests__/routes/profile.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/routes/profile.test.js b/__tests__/routes/profile.test.js index e9d5cd7..2e817e1 100644 --- a/__tests__/routes/profile.test.js +++ b/__tests__/routes/profile.test.js @@ -39,7 +39,7 @@ describe('Profile', () => { }}) expect(res.status).toBe(200); - expect(res.body.message).toBe('Your email is changed. Please check your email for confirmation'); + expect(res.body.message).toBe('Your email has changed. Please check your email for confirmation'); expect(res.body.user.firstName).toBe(profile.firstName); expect(res.body.user.lastName).toBe(profile.lastName); expect(res.body.user.username).toBe(profile.username);