From 0220fc745a1595fa305f8433b483025580a3ae99 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:18:58 +0100 Subject: [PATCH 01/27] Resources --- app/routes/auth/index.js | 34 ++++++++++++++++++++++ app/routes/auth/login.js | 5 ++++ app/routes/auth/register.js | 5 ++++ app/routes/index.js | 4 ++- app/routes/note/all.js | 4 +-- app/routes/note/create.js | 0 app/routes/note/delete.js | 0 app/routes/note/index.js | 29 +++++++++++++++---- app/routes/note/single.js | 4 +-- app/routes/note/update.js | 0 app/routes/user/create.js | 0 app/routes/user/delete.js | 0 app/routes/user/index.js | 57 +++++++++++++++++++++++++++++++++---- app/routes/user/profile.js | 5 ++++ app/routes/user/update.js | 0 15 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 app/routes/auth/index.js create mode 100644 app/routes/auth/login.js create mode 100644 app/routes/auth/register.js create mode 100644 app/routes/note/create.js create mode 100644 app/routes/note/delete.js create mode 100644 app/routes/note/update.js create mode 100644 app/routes/user/create.js create mode 100644 app/routes/user/delete.js create mode 100644 app/routes/user/profile.js create mode 100644 app/routes/user/update.js diff --git a/app/routes/auth/index.js b/app/routes/auth/index.js new file mode 100644 index 0000000..3b30775 --- /dev/null +++ b/app/routes/auth/index.js @@ -0,0 +1,34 @@ +const auth = require('express').Router(); + +const register = require('./register'); +const login = require('./login'); + +/** + * @api {post} /auth/register Register + * @apiName Register + * @apiGroup Auth + * + * @apiParam {String} firstname Firstname of the user. + * @apiParam {String} lastname Lastname of the user. + * @apiParam {String} username username of the user. + * @apiParam {String} password password of the user. + * + * @apiSuccess {Array} Array Array of Note objects. + */ +auth.post('/register', register); + +/** + * @api {post} /auth/login Request JWT token + * @apiName Login + * @apiGroup Auth + * + * @apiParam {String} username username of the user. + * @apiParam {String} password password of the user. + * + * @apiSuccess {string} jwt JWT token. + */ +auth.post('/login', login); + +//note.post('/rester-password', reset) + +module.exports = auth; diff --git a/app/routes/auth/login.js b/app/routes/auth/login.js new file mode 100644 index 0000000..74da097 --- /dev/null +++ b/app/routes/auth/login.js @@ -0,0 +1,5 @@ +module.exports = (req, res) => { + const auth = []; + + res.status(200).json({ auth }); +}; diff --git a/app/routes/auth/register.js b/app/routes/auth/register.js new file mode 100644 index 0000000..74da097 --- /dev/null +++ b/app/routes/auth/register.js @@ -0,0 +1,5 @@ +module.exports = (req, res) => { + const auth = []; + + res.status(200).json({ auth }); +}; diff --git a/app/routes/index.js b/app/routes/index.js index e8d2830..f0ceddd 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -2,6 +2,7 @@ const routes = require('express').Router(); const bodyParser = require('body-parser'); // Require routes +const auth = require('./auth'); const user = require('./user'); const note = require('./note'); @@ -12,7 +13,7 @@ routes.use(bodyParser.json()); routes.use((req, res, next) => { // do logging - console.log('Something is happening.'); + console.log(`Resource requested: ${req.method} ${req.originalUrl}`); next(); // make sure we go to the next routes and don't stop here }); @@ -20,6 +21,7 @@ routes.get('/', (req, res) => { res.status(200).json({ message: 'Hello world!' }); }); +routes.use('/auth', auth); routes.use('/user', user); routes.use('/note', note); diff --git a/app/routes/note/all.js b/app/routes/note/all.js index 5e6ce1b..b0c2789 100644 --- a/app/routes/note/all.js +++ b/app/routes/note/all.js @@ -1,5 +1,5 @@ module.exports = (req, res) => { - const users = []; + const notes = []; - res.status(200).json({ users }); + res.status(200).json({ notes }); }; diff --git a/app/routes/note/create.js b/app/routes/note/create.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/note/delete.js b/app/routes/note/delete.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/note/index.js b/app/routes/note/index.js index c7c889a..88ef8af 100644 --- a/app/routes/note/index.js +++ b/app/routes/note/index.js @@ -1,9 +1,10 @@ const note = require('express').Router(); + const all = require('./all'); const single = require('./single'); -//const create = require('./create'); -//const update = require('./update'); -//const delete = require('./delete'); +const create = require('./create'); +const update = require('./update'); +const remove = require('./delete'); /** * @api {get} /note Request all notes @@ -24,10 +25,26 @@ note.get('/', all); * @apiSuccess {string} title Title of the note. * @apiSuccess {string} text Text of the note. */ -note.get('/:noteId', single); +note.get('/:id', single); + +/** + * @api {post} /note Create note + * @apiName CreateNote + * @apiGroup Note + * + * @apiSuccess {Object} Object Created note. + */ +note.post('/', all); + +/** + * @api {delete} /note/:id Delete a note + * @apiName DeleteNote + * @apiGroup Note + */ +note.delete('/:id', all); //note.post('/', create) -//note.post('/:noteId', update) -//note.post('/:noteId', delete) +//note.put('/:noteId', update) +//note.delete('/:noteId', remove) module.exports = note; diff --git a/app/routes/note/single.js b/app/routes/note/single.js index fda0e54..bcbb2f1 100644 --- a/app/routes/note/single.js +++ b/app/routes/note/single.js @@ -1,5 +1,5 @@ module.exports = (req, res) => { - const user = req.model; + const note = req.model; - res.status(200).json({ user }); + res.status(200).json({ note }); }; diff --git a/app/routes/note/update.js b/app/routes/note/update.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/user/create.js b/app/routes/user/create.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/user/delete.js b/app/routes/user/delete.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/user/index.js b/app/routes/user/index.js index f49e044..3bc40d6 100644 --- a/app/routes/user/index.js +++ b/app/routes/user/index.js @@ -1,9 +1,11 @@ const user = require('express').Router(); + const all = require('./all'); +const profile = require('./profile'); const single = require('./single'); -//const create = require('./create'); -//const update = require('./update'); -//const delete = require('./delete'); +const create = require('./create'); +const update = require('./update'); +const remove = require('./delete'); /** * @api {get} /user Request all Users information @@ -12,7 +14,7 @@ const single = require('./single'); * * @apiParam {Number} id Users unique ID. * - * @apiSuccess {Array} Array Array of User objects. + * @apiSuccess {Array} Array User objects. */ user.get('/', all); @@ -29,8 +31,51 @@ user.get('/', all); */ user.get('/:userId', single); +/** + * @api {get} /user/me Request current account information + * @apiName GetUser + * @apiGroup User + * + * @apiSuccess {String} firstname Firstname of the User. + * @apiSuccess {String} lastname Lastname of the User. + * @apiSuccess {String} username Username of the User. + */ +user.get('/me', profile); + +/** + * @api {put} /user/me Update current account information + * @apiName UpdateUser + * @apiGroup User + * + * @apiParam {String} firstname Firstname of the User. + * @apiParam {String} lastname Lastname of the User. + * @apiParam {String} username Username of the User. + */ +user.put('/me', profile); + +/** + * @api {delete} /user/me Delete current account + * @apiName DeleteUser + * @apiGroup User + * + * @apiParam {String} firstname Firstname of the User. + * @apiParam {String} lastname Lastname of the User. + * @apiParam {String} username Username of the User. + */ + user.delete('/me', profile); + + /** + * @api {get} /user/me/notes Get notes created by this account + * @apiName GetNotes + * @apiGroup User,Note + * + * @apiSuccess {string} title Title of the note. + * @apiSuccess {string} text Text of the note. + */ + user.get('/me/notes', profile); + //user.post('/', create) -//user.post('/:userId', update) -//user.post('/:userId', delete) +//user.put('/:userId', update) +//user.delete('/:userId', remove) module.exports = user; diff --git a/app/routes/user/profile.js b/app/routes/user/profile.js new file mode 100644 index 0000000..0e97c8b --- /dev/null +++ b/app/routes/user/profile.js @@ -0,0 +1,5 @@ +module.exports = (req, res) => { + const user = {}; + + res.status(200).json({ user }); +}; diff --git a/app/routes/user/update.js b/app/routes/user/update.js new file mode 100644 index 0000000..e69de29 From 5282b3c4fac1714f4912aff9a75b95c23f7eafcb Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:19:13 +0100 Subject: [PATCH 02/27] Models --- app/models/user.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/app/models/user.js b/app/models/user.js index cd8f98b..97f136f 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -1,11 +1,25 @@ var mongoose = require('mongoose'); var Schema = mongoose.Schema; +var bcrypt = require('bcrypt-nodejs'); -var UserSchema = new Schema({ - firstname: String, - lastname: String, - username: String, - password: String +var UserSchema = new Schema({ + firstname: { + type: String, + required: true + }, + lastname: { + type: String, + required: true + }, + username: { + type: String, + unique: true, + required: true + }, + password: { + type: String, + required: true + } }); module.exports = mongoose.model('User', UserSchema); From d6aeee2eae1ff6e96972adb89441fae7b1097f0c Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:19:22 +0100 Subject: [PATCH 03/27] Configuration --- config/database.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 config/database.js diff --git a/config/database.js b/config/database.js new file mode 100644 index 0000000..683002c --- /dev/null +++ b/config/database.js @@ -0,0 +1,4 @@ +module.exports = { + 'secret':'admin', + 'database': 'mongodb://localhost/mooc-api' +}; From f87986fd69752972db41ac01e58d15a0a42aa4b6 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:19:39 +0100 Subject: [PATCH 04/27] Docs --- docs/api_data.js | 276 +++++++++++++++++++++++++++++++++++++++++- docs/api_data.json | 276 +++++++++++++++++++++++++++++++++++++++++- docs/api_project.js | 2 +- docs/api_project.json | 2 +- 4 files changed, 552 insertions(+), 4 deletions(-) diff --git a/docs/api_data.js b/docs/api_data.js index 994318b..6f0166d 100644 --- a/docs/api_data.js +++ b/docs/api_data.js @@ -1,4 +1,137 @@ define({ "api": [ + { + "type": "post", + "url": "/auth/login", + "title": "Request JWT token", + "name": "Login", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

username of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "

password of the user.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "jwt", + "description": "

JWT token.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, + { + "type": "post", + "url": "/auth/register", + "title": "Register", + "name": "Register", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

username of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "

password of the user.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Array", + "optional": false, + "field": "Array", + "description": "

Array of Note objects.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, + { + "type": "post", + "url": "/note", + "title": "Create note", + "name": "CreateNote", + "group": "Note", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Object", + "optional": false, + "field": "Object", + "description": "

Created note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, + { + "type": "delete", + "url": "/note/:id", + "title": "Delete a note", + "name": "DeleteNote", + "group": "Note", + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, { "type": "get", "url": "/note", @@ -65,6 +198,43 @@ define({ "api": [ "filename": "app/routes/note/index.js", "groupTitle": "Note" }, + { + "type": "delete", + "url": "/user/me", + "title": "Delete current account", + "name": "DeleteUser", + "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, { "type": "get", "url": "/user/:id", @@ -115,6 +285,43 @@ define({ "api": [ "filename": "app/routes/user/index.js", "groupTitle": "User" }, + { + "type": "get", + "url": "/user/me", + "title": "Request current account information", + "name": "GetUser", + "group": "User", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, { "type": "get", "url": "/user", @@ -142,7 +349,7 @@ define({ "api": [ "type": "Array", "optional": false, "field": "Array", - "description": "

Array of User objects.

" + "description": "

User objects.

" } ] } @@ -150,5 +357,72 @@ define({ "api": [ "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" + }, + { + "type": "put", + "url": "/user/me", + "title": "Update current account information", + "name": "UpdateUser", + "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, + { + "type": "get", + "url": "/user/me/notes", + "title": "Get notes created by this account", + "name": "GetNotes", + "group": "User_Note", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "title", + "description": "

Title of the note.

" + }, + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "text", + "description": "

Text of the note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User_Note" } ] }); diff --git a/docs/api_data.json b/docs/api_data.json index 8a28812..da25f47 100644 --- a/docs/api_data.json +++ b/docs/api_data.json @@ -1,4 +1,137 @@ [ + { + "type": "post", + "url": "/auth/login", + "title": "Request JWT token", + "name": "Login", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

username of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "

password of the user.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "jwt", + "description": "

JWT token.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, + { + "type": "post", + "url": "/auth/register", + "title": "Register", + "name": "Register", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

username of the user.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "password", + "description": "

password of the user.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Array", + "optional": false, + "field": "Array", + "description": "

Array of Note objects.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, + { + "type": "post", + "url": "/note", + "title": "Create note", + "name": "CreateNote", + "group": "Note", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Object", + "optional": false, + "field": "Object", + "description": "

Created note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, + { + "type": "delete", + "url": "/note/:id", + "title": "Delete a note", + "name": "DeleteNote", + "group": "Note", + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, { "type": "get", "url": "/note", @@ -65,6 +198,43 @@ "filename": "app/routes/note/index.js", "groupTitle": "Note" }, + { + "type": "delete", + "url": "/user/me", + "title": "Delete current account", + "name": "DeleteUser", + "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, { "type": "get", "url": "/user/:id", @@ -115,6 +285,43 @@ "filename": "app/routes/user/index.js", "groupTitle": "User" }, + { + "type": "get", + "url": "/user/me", + "title": "Request current account information", + "name": "GetUser", + "group": "User", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, { "type": "get", "url": "/user", @@ -142,7 +349,7 @@ "type": "Array", "optional": false, "field": "Array", - "description": "

Array of User objects.

" + "description": "

User objects.

" } ] } @@ -150,5 +357,72 @@ "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" + }, + { + "type": "put", + "url": "/user/me", + "title": "Update current account information", + "name": "UpdateUser", + "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "firstname", + "description": "

Firstname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "lastname", + "description": "

Lastname of the User.

" + }, + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "username", + "description": "

Username of the User.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User" + }, + { + "type": "get", + "url": "/user/me/notes", + "title": "Get notes created by this account", + "name": "GetNotes", + "group": "User_Note", + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "title", + "description": "

Title of the note.

" + }, + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "text", + "description": "

Text of the note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/user/index.js", + "groupTitle": "User_Note" } ] diff --git a/docs/api_project.js b/docs/api_project.js index 823e5e8..a71dc02 100644 --- a/docs/api_project.js +++ b/docs/api_project.js @@ -8,7 +8,7 @@ define({ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2018-11-12T15:27:44.007Z", + "time": "2018-11-12T17:15:53.319Z", "url": "http://apidocjs.com", "version": "0.17.7" } diff --git a/docs/api_project.json b/docs/api_project.json index 1fa8c5f..96d6d09 100644 --- a/docs/api_project.json +++ b/docs/api_project.json @@ -8,7 +8,7 @@ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2018-11-12T15:27:44.007Z", + "time": "2018-11-12T17:15:53.319Z", "url": "http://apidocjs.com", "version": "0.17.7" } From 1b7da6d9b2404d664169aa142acb334cdbac87a7 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:19:58 +0100 Subject: [PATCH 05/27] 404 error middleware --- index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.js b/index.js index 59bc8d5..d047037 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,10 @@ const port = process.env.PORT || 8080; // set our port app.use('/', routes); +app.use(function(req, res) { + res.status(404).json({ message: 'Resource not found.' }); +}); + // Start the server app.listen(port); console.log('Server started on port ' + port); From 634d75fbe53632b0782efe57f637e5fc20cfc734 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:20:11 +0100 Subject: [PATCH 06/27] bcrypt package --- package-lock.json | 5 +++++ package.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 7eec140..86f4fd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -88,6 +88,11 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "bcrypt-nodejs": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", + "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=" + }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", diff --git a/package.json b/package.json index b918d9b..2a3128a 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "", "main": "index.js", "dependencies": { + "bcrypt-nodejs": "0.0.3", "body-parser": "^1.18.3", "express": "^4.16.4", "mongoose": "^5.3.11" @@ -15,7 +16,7 @@ "title": "Mooc API" }, "scripts": { - "doc":"apidoc -i ./app/routes -o ./docs", + "doc": "apidoc -i ./app/routes -o ./docs", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { From b3481c3f73cad75e9c48edfe4632b04c3ca42d9f Mon Sep 17 00:00:00 2001 From: sundowndev Date: Mon, 12 Nov 2018 18:25:13 +0100 Subject: [PATCH 07/27] JWT & passport packages --- package-lock.json | 109 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 86f4fd6..c7e9346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -130,6 +130,11 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -259,6 +264,14 @@ "kuler": "1.0.x" } }, + "ecdsa-sig-formatter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", + "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -501,6 +514,48 @@ "graceful-fs": "^4.1.6" } }, + "jsonwebtoken": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", + "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", + "requires": { + "jws": "^3.1.5", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "jwa": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", + "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.10", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", + "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", + "requires": { + "jwa": "^1.1.5", + "safe-buffer": "^5.0.1" + } + }, "kareem": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", @@ -543,6 +598,41 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "logform": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", @@ -741,6 +831,20 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" }, + "passport": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", + "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -752,6 +856,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", diff --git a/package.json b/package.json index 2a3128a..f6679a7 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "bcrypt-nodejs": "0.0.3", "body-parser": "^1.18.3", "express": "^4.16.4", - "mongoose": "^5.3.11" + "jsonwebtoken": "^8.3.0", + "mongoose": "^5.3.11", + "passport": "^0.4.0" }, "devDependencies": { "apidoc": "^0.17.7" From b1abecc262a48eee805c842aba9937c2ca19cfa5 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 11:15:47 +0100 Subject: [PATCH 08/27] Install eslint --- .eslintignore | 2 + .eslintrc.json | 3 + package-lock.json | 1448 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 10 +- 4 files changed, 1461 insertions(+), 2 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1a487cf --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +docs +ode_modules diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6f67564 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "airbnb-base" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c7e9346..a1e8fb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,26 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -13,6 +33,51 @@ "negotiator": "0.6.1" } }, + "acorn": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", + "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz", + "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==", + "dev": true + }, + "ajv": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", + "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "apidoc": { "version": "0.17.7", "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.7.tgz", @@ -69,11 +134,52 @@ "sprintf-js": "~1.0.2" } }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, "async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", @@ -82,6 +188,15 @@ "lodash": "^4.17.10" } }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -135,11 +250,70 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", @@ -209,6 +383,12 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -235,6 +415,25 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -243,6 +442,35 @@ "ms": "2.0.0" } }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + } + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -264,6 +492,15 @@ "kuler": "1.0.x" } }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "ecdsa-sig-formatter": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", @@ -277,6 +514,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", + "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", + "dev": true + }, "enabled": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", @@ -303,11 +546,297 @@ "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==", "dev": true }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + } + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz", + "integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.5.3", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "imurmurhash": "^0.1.4", + "inquirer": "^6.1.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.12.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.0.2", + "text-table": "^0.2.0" + }, + "dependencies": { + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "eslint-config-airbnb": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz", + "integrity": "sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^13.1.0", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4" + } + }, + "eslint-config-airbnb-base": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz", + "integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==", + "dev": true, + "requires": { + "eslint-restricted-globals": "^0.1.1", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^1.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", + "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", + "dev": true, + "requires": { + "contains-path": "^0.1.0", + "debug": "^2.6.8", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.1", + "eslint-module-utils": "^2.2.0", + "has": "^1.0.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.3", + "read-pkg-up": "^2.0.0", + "resolve": "^1.6.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz", + "integrity": "sha512-7gSSmwb3A+fQwtw0arguwMdOdzmKUgnUcbSNlo+GjKLAQFuC2EZxWqG9XHRI8VscBJD5a8raz3RuxQNFW+XJbw==", + "dev": true, + "requires": { + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.1", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^6.5.1", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1" + } + }, + "eslint-plugin-react": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", + "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1", + "prop-types": "^15.6.2" + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", + "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", + "dev": true, + "requires": { + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -357,6 +886,46 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fast-safe-stringify": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", @@ -369,6 +938,25 @@ "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==", "dev": true }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, "finalhandler": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", @@ -390,6 +978,28 @@ } } }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.2.tgz", + "integrity": "sha512-KByBY8c98sLUAGpnmjEdWTrtrLZRtZdwds+kAL/ciFXTCb7AZgqKsAnVnYFQj1hxepwO8JKN/8AsRWwLq+RK0A==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "del": "^3.0.0", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -428,6 +1038,18 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -442,12 +1064,66 @@ "path-is-absolute": "^1.0.0" } }, + "globals": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, "http-errors": { "version": "1.6.3", "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -467,6 +1143,18 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -482,6 +1170,27 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "inquirer": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", + "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, "ipaddr.js": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", @@ -493,18 +1202,133 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "jsonfile": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", @@ -537,6 +1361,15 @@ } } }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "^3.0.3" + } + }, "jwa": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", @@ -579,6 +1412,16 @@ "colornames": "^1.1.1" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "linkify-it": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", @@ -588,6 +1431,44 @@ "uc.micro": "^1.0.1" } }, + "load-json-file": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -654,6 +1535,15 @@ } } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "markdown-it": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", @@ -712,6 +1602,12 @@ "mime-db": "~1.37.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -721,6 +1617,21 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "mongodb": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.8.tgz", @@ -798,11 +1709,77 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -826,6 +1803,74 @@ "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", "dev": true }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -845,28 +1890,130 @@ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": 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==", "dev": true }, + "progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", + "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "dev": true + }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "dev": true, + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -876,6 +2023,12 @@ "ipaddr.js": "1.8.0" } }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -897,6 +2050,38 @@ "unpipe": "1.0.0" } }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } + } + }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -917,6 +2102,30 @@ "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, "require_optional": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", @@ -926,11 +2135,57 @@ "semver": "^5.1.0" } }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", + "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -998,6 +2253,27 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -1007,6 +2283,15 @@ "is-arrayish": "^0.3.1" } }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -1021,6 +2306,38 @@ "memory-pager": "^1.0.2" } }, + "spdx-correct": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", + "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", + "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1038,6 +2355,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -1047,18 +2374,96 @@ "safe-buffer": "~5.1.0" } }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "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=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", + "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", + "dev": true, + "requires": { + "ajv": "^6.5.3", + "lodash": "^4.17.10", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", "dev": true }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", @@ -1085,6 +2490,15 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1096,11 +2510,30 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "winston": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz", @@ -1128,11 +2561,26 @@ "triple-beam": "^1.2.0" } }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } } } } diff --git a/package.json b/package.json index f6679a7..0bae3f5 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,20 @@ "passport": "^0.4.0" }, "devDependencies": { - "apidoc": "^0.17.7" + "apidoc": "^0.17.7", + "eslint": "^5.9.0", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-airbnb-base": "^13.1.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-jsx-a11y": "^6.1.2", + "eslint-plugin-react": "^7.11.1" }, "apidoc": { "title": "Mooc API" }, "scripts": { "doc": "apidoc -i ./app/routes -o ./docs", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "eslint ./" }, "repository": { "type": "git", From 51ab76f613bd84b89aeb240b563cfbd97ee20346 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:46:28 +0100 Subject: [PATCH 09/27] Database config --- app/db/db.config.js | 9 +++++++++ app/db/db.connect.js | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 app/db/db.config.js create mode 100644 app/db/db.connect.js diff --git a/app/db/db.config.js b/app/db/db.config.js new file mode 100644 index 0000000..390b5e9 --- /dev/null +++ b/app/db/db.config.js @@ -0,0 +1,9 @@ +module.exports = { + name: 'api-mooc', + host: process.env.HOST_MONGODB || '127.0.0.1:27017', + opts: { + promiseLibrary: global.Promise, + useNewUrlParser: true, + useCreateIndex: true, + }, +}; diff --git a/app/db/db.connect.js b/app/db/db.connect.js new file mode 100644 index 0000000..9f7747f --- /dev/null +++ b/app/db/db.connect.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); + +const UserSchema = require('../models/user'); +const NoteSchema = require('../models/note'); + +const db = require('./db.config'); + +mongoose.connect(`mongodb://${db.host}/${db.name}`, db.opts); + +mongoose.connection.on('connected', () => { + mongoose.model('User', UserSchema); + mongoose.model('Note', NoteSchema); +}); From 78fd638195507bde17d4db8bdf26c110f2d9eb2b Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:46:36 +0100 Subject: [PATCH 10/27] Travis config --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5d1f68e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: node_js + +node_js: + - "7" + - "8" + +before_script: + - npm install +script: npm run test From 95c8a65bc238271004d0e53ad0b627b1fd36b76e Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:46:44 +0100 Subject: [PATCH 11/27] Models --- app/models/note.js | 19 ++++++++++++------- app/models/user.js | 27 ++++++++++----------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/models/note.js b/app/models/note.js index 60f5f7c..e1be838 100644 --- a/app/models/note.js +++ b/app/models/note.js @@ -1,9 +1,14 @@ -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; +const mongoose = require('mongoose'); -var NoteSchema = new Schema({ - title: String, - text: String -}); +const { Schema } = mongoose; -module.exports = mongoose.model('Note', NoteSchema); +const NoteSchema = new Schema({ + title: { + type: String, required: [true, "can't be blank"], + }, + text: { + type: String, required: [true, "can't be blank"], + }, +}, { timestamps: true }); + +module.exports = NoteSchema; diff --git a/app/models/user.js b/app/models/user.js index 97f136f..e0bbbe5 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -1,25 +1,18 @@ -var mongoose = require('mongoose'); -var Schema = mongoose.Schema; -var bcrypt = require('bcrypt-nodejs'); +const mongoose = require('mongoose'); -var UserSchema = new Schema({ +const { Schema } = mongoose; + +const UserSchema = new Schema({ firstname: { - type: String, - required: true + type: String, required: [true, "can't be blank"], }, lastname: { - type: String, - required: true + type: String, required: [true, "can't be blank"], }, username: { - type: String, - unique: true, - required: true + type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/^[a-zA-Z0-9]+$/, 'is invalid'], index: true, }, - password: { - type: String, - required: true - } -}); + password: String, +}, { timestamps: true }); -module.exports = mongoose.model('User', UserSchema); +module.exports = UserSchema; From 5181a9100aa0163340a3f4c88be82870648479c5 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:47:30 +0100 Subject: [PATCH 12/27] Auth routes --- app/routes/auth/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/auth/index.js b/app/routes/auth/index.js index 3b30775..e848ad8 100644 --- a/app/routes/auth/index.js +++ b/app/routes/auth/index.js @@ -25,10 +25,10 @@ auth.post('/register', register); * @apiParam {String} username username of the user. * @apiParam {String} password password of the user. * - * @apiSuccess {string} jwt JWT token. + * @apiSuccess {string} jwt_token JWT token. */ auth.post('/login', login); -//note.post('/rester-password', reset) +// note.post('/rester-password', reset) module.exports = auth; From b35a5b26c0fb04c9089735912e27690a4c15582f Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:47:42 +0100 Subject: [PATCH 13/27] Note routes --- app/routes/note/all.js | 13 ++++++++++--- app/routes/note/create.js | 17 +++++++++++++++++ app/routes/note/delete.js | 18 ++++++++++++++++++ app/routes/note/index.js | 19 ++++++++++++++----- app/routes/note/single.js | 16 +++++++++++++--- app/routes/note/update.js | 15 +++++++++++++++ 6 files changed, 87 insertions(+), 11 deletions(-) diff --git a/app/routes/note/all.js b/app/routes/note/all.js index b0c2789..a64ac2c 100644 --- a/app/routes/note/all.js +++ b/app/routes/note/all.js @@ -1,5 +1,12 @@ -module.exports = (req, res) => { - const notes = []; +const mongoose = require('mongoose'); - res.status(200).json({ notes }); +module.exports = (req, res) => { + const NoteModel = mongoose.model('Note'); + + NoteModel.find({}) + .lean() + .exec() + .then((result) => { + res.status(200).json(result); + }); }; diff --git a/app/routes/note/create.js b/app/routes/note/create.js index e69de29..a0b6c2a 100644 --- a/app/routes/note/create.js +++ b/app/routes/note/create.js @@ -0,0 +1,17 @@ +const mongoose = require('mongoose'); + +// TODO: verify auth + +module.exports = (req, res) => { + const NoteModel = mongoose.model('Note'); + + const Note = new NoteModel({ title: req.body.title, text: req.body.text }); + + Note.save((err) => { + if (err) { + return res.status(400).json({ success: false, msg: 'Title and text must not be blank.' }); + } + + return res.status(200).json(Note); + }); +}; diff --git a/app/routes/note/delete.js b/app/routes/note/delete.js index e69de29..68fe7d2 100644 --- a/app/routes/note/delete.js +++ b/app/routes/note/delete.js @@ -0,0 +1,18 @@ +const mongoose = require('mongoose'); + +// TODO: verify auth +// TODO: verify owner + +module.exports = (req, res) => { + const NoteModel = mongoose.model('Note'); + + NoteModel.findByIdAndDelete(req.params.id) + .lean() + .exec() + .then(() => { + res.status(200).json({ success: true, msg: 'Note deleted.' }); + }) + .catch(() => { + res.status(404).json({ success: false, msg: 'Note does not exists.' }); + }); +}; diff --git a/app/routes/note/index.js b/app/routes/note/index.js index 88ef8af..dbdf13e 100644 --- a/app/routes/note/index.js +++ b/app/routes/note/index.js @@ -34,17 +34,26 @@ note.get('/:id', single); * * @apiSuccess {Object} Object Created note. */ -note.post('/', all); +note.post('/', create); /** * @api {delete} /note/:id Delete a note * @apiName DeleteNote * @apiGroup Note + * + * @apiParam {Number} id Note id. */ -note.delete('/:id', all); +note.delete('/:id', remove); -//note.post('/', create) -//note.put('/:noteId', update) -//note.delete('/:noteId', remove) +/** + * @api {put} /note/:id Update a note + * @apiName UpdateNote + * @apiGroup Note + * + * @apiParam {Number} id Note id. + * + * @apiSuccess {Object} Object Updated note. + */ +note.put('/:id', update); module.exports = note; diff --git a/app/routes/note/single.js b/app/routes/note/single.js index bcbb2f1..5be1fa8 100644 --- a/app/routes/note/single.js +++ b/app/routes/note/single.js @@ -1,5 +1,15 @@ -module.exports = (req, res) => { - const note = req.model; +const mongoose = require('mongoose'); - res.status(200).json({ note }); +module.exports = (req, res) => { + const NoteModel = mongoose.model('Note'); + + NoteModel.find({ _id: req.params.id }) + .lean() + .exec() + .then((result) => { + res.status(200).json(result); + }) + .catch(() => { + res.status(404).json({ success: false, msg: 'Note does not exists.' }); + }); }; diff --git a/app/routes/note/update.js b/app/routes/note/update.js index e69de29..5be1fa8 100644 --- a/app/routes/note/update.js +++ b/app/routes/note/update.js @@ -0,0 +1,15 @@ +const mongoose = require('mongoose'); + +module.exports = (req, res) => { + const NoteModel = mongoose.model('Note'); + + NoteModel.find({ _id: req.params.id }) + .lean() + .exec() + .then((result) => { + res.status(200).json(result); + }) + .catch(() => { + res.status(404).json({ success: false, msg: 'Note does not exists.' }); + }); +}; From 2091dae63b11ff2522d8f47e709b0a61966d0d3e Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:47:56 +0100 Subject: [PATCH 14/27] User routes --- app/routes/user/all.js | 12 +++++++++--- app/routes/user/create.js | 12 ++++++++++++ app/routes/user/index.js | 18 +++++++++--------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/app/routes/user/all.js b/app/routes/user/all.js index 5e6ce1b..9e1d309 100644 --- a/app/routes/user/all.js +++ b/app/routes/user/all.js @@ -1,5 +1,11 @@ -module.exports = (req, res) => { - const users = []; +const mongoose = require('mongoose'); - res.status(200).json({ users }); +module.exports = (req, res) => { + const UserModel = mongoose.model('User'); + const users = UserModel.find() + .lean() + .exec() + .then(() => { + res.status(200).json(users); + }); }; diff --git a/app/routes/user/create.js b/app/routes/user/create.js index e69de29..7098f3c 100644 --- a/app/routes/user/create.js +++ b/app/routes/user/create.js @@ -0,0 +1,12 @@ +const Joi = require('joi'); +// const jwt = require('jsonwebtoken'); +// const bcrypt = require('bcrypt-nodejs'); + +const schema = Joi.object().keys({ + firstname: Joi.string().alphanum().min(2), + lastname: Joi.string().alphanum().min(2), + username: Joi.string().alphanum().min(3).max(30) + .required(), + password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/), + access_token: [Joi.string(), Joi.number()], +}).with('username').without('password', 'access_token'); diff --git a/app/routes/user/index.js b/app/routes/user/index.js index 3bc40d6..f80dee0 100644 --- a/app/routes/user/index.js +++ b/app/routes/user/index.js @@ -3,9 +3,9 @@ const user = require('express').Router(); const all = require('./all'); const profile = require('./profile'); const single = require('./single'); -const create = require('./create'); -const update = require('./update'); -const remove = require('./delete'); +// const create = require('./create'); +// const update = require('./update'); +// const remove = require('./delete'); /** * @api {get} /user Request all Users information @@ -62,9 +62,9 @@ user.put('/me', profile); * @apiParam {String} lastname Lastname of the User. * @apiParam {String} username Username of the User. */ - user.delete('/me', profile); +user.delete('/me', profile); - /** +/** * @api {get} /user/me/notes Get notes created by this account * @apiName GetNotes * @apiGroup User,Note @@ -72,10 +72,10 @@ user.put('/me', profile); * @apiSuccess {string} title Title of the note. * @apiSuccess {string} text Text of the note. */ - user.get('/me/notes', profile); +user.get('/me/notes', profile); -//user.post('/', create) -//user.put('/:userId', update) -//user.delete('/:userId', remove) +// user.post('/', create) +// user.put('/:userId', update) +// user.delete('/:userId', remove) module.exports = user; From 0df1d302dafe5fc5d9df907f289a429af61e4fa9 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:48:33 +0100 Subject: [PATCH 15/27] Routes index --- app/routes/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/routes/index.js b/app/routes/index.js index f0ceddd..6137bc5 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -12,9 +12,9 @@ routes.use(bodyParser.urlencoded({ extended: true })); routes.use(bodyParser.json()); routes.use((req, res, next) => { - // do logging - console.log(`Resource requested: ${req.method} ${req.originalUrl}`); - next(); // make sure we go to the next routes and don't stop here + // do logging + console.log(`Resource requested: ${req.method} ${req.originalUrl}`); + next(); // make sure we go to the next routes and don't stop here }); routes.get('/', (req, res) => { From 7b29aedf2c0b5d2c83ce506f4c16da17baf8052a Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:48:46 +0100 Subject: [PATCH 16/27] Delete server.js --- app/server.js | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 app/server.js diff --git a/app/server.js b/app/server.js deleted file mode 100644 index e73d315..0000000 --- a/app/server.js +++ /dev/null @@ -1,5 +0,0 @@ -var mongoose = require('mongoose'); - -mongoose.connect('mongodb://node:node@novus.modulusmongo.net:27017/Iganiq8o'); - -var User = require('./app/models/user'); From af3f42397dcc152c5a76131576a80d4291128549 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:48:56 +0100 Subject: [PATCH 17/27] Entry point --- index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index d047037..ff252bf 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +require('./app/db/db.connect'); + const express = require('express'); const routes = require('./app/routes'); @@ -7,10 +9,10 @@ const port = process.env.PORT || 8080; // set our port app.use('/', routes); -app.use(function(req, res) { - res.status(404).json({ message: 'Resource not found.' }); +app.use((req, res) => { + res.status(404).json({ message: 'Resource not found.' }); }); // Start the server app.listen(port); -console.log('Server started on port ' + port); +console.log(`Server started on port ${port}`); From 7f65fee7254d03c2a552d74e4c70fb8e4d9b2f88 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:49:14 +0100 Subject: [PATCH 18/27] Database config --- config/database.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/database.js b/config/database.js index 683002c..e830336 100644 --- a/config/database.js +++ b/config/database.js @@ -1,4 +1,4 @@ module.exports = { - 'secret':'admin', - 'database': 'mongodb://localhost/mooc-api' + secret: 'admin', + database: 'mongodb://localhost/mooc-api', }; From 145389a6193778ca037869ee060438f3c3472099 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Tue, 13 Nov 2018 18:49:39 +0100 Subject: [PATCH 19/27] Install Joi package --- package-lock.json | 34 ++++++++++++++++++++++++++++++++-- package.json | 1 + 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1e8fb4..689f9ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1118,6 +1118,11 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "hoek": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.0.3.tgz", + "integrity": "sha512-TU6RyZ/XaQCTWRLrdqZZtZqwxUVr6PDMfi6MlWNURZ7A6czanQqX4pFE1mdOUQR9FdPCsZ0UzL8jI/izZ+eBSQ==" + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -1295,12 +1300,30 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "requires": { + "punycode": "2.x.x" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "joi": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.0.6.tgz", + "integrity": "sha512-mKXPSNYMG3taVBZemQj3pPOlMZGrnnu14JKAC6AHg6jJVX35L7oDk89ss1sHj+laDSEh3mD2PmeheI5k6Aw8nQ==", + "requires": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2026,8 +2049,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { "version": "6.5.2", @@ -2443,6 +2465,14 @@ "os-tmpdir": "~1.0.2" } }, + "topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "requires": { + "hoek": "6.x.x" + } + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", diff --git a/package.json b/package.json index 0bae3f5..17bcd24 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "bcrypt-nodejs": "0.0.3", "body-parser": "^1.18.3", "express": "^4.16.4", + "joi": "^14.0.6", "jsonwebtoken": "^8.3.0", "mongoose": "^5.3.11", "passport": "^0.4.0" From e889d37333454038026fdaf4da11569215b7c53d Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:14:57 +0100 Subject: [PATCH 20/27] User schema --- app/schemas/user.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 app/schemas/user.js diff --git a/app/schemas/user.js b/app/schemas/user.js new file mode 100644 index 0000000..16dae6a --- /dev/null +++ b/app/schemas/user.js @@ -0,0 +1,25 @@ +const Joi = require('joi'); + +module.exports = (req, res, next) => { + const schema = Joi.object().keys({ + firstname: Joi.string().min(2).required(), + lastname: Joi.string().min(2).required(), + username: Joi.string().alphanum().min(3).max(30) + .required(), + password: Joi.string().required(), + }); + + Joi.validate({ + firstname: req.body.firstname, + lastname: req.body.lastname, + username: req.body.username, + password: req.body.password, + }, + schema, (validateErr) => { + if (validateErr) { + return next({ status: 400, message: 'Form is invalid.', error: validateErr }); + } + + return next(); + }); +}; From 78604bc8bdd3c601b089f1f309c697eca57b9273 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:15:20 +0100 Subject: [PATCH 21/27] Auth routes --- app/routes/auth/index.js | 8 +++++--- app/routes/auth/login.js | 30 +++++++++++++++++++++++++++--- app/routes/auth/register.js | 30 +++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/app/routes/auth/index.js b/app/routes/auth/index.js index e848ad8..61ba948 100644 --- a/app/routes/auth/index.js +++ b/app/routes/auth/index.js @@ -3,6 +3,8 @@ const auth = require('express').Router(); const register = require('./register'); const login = require('./login'); +const UserSchema = require('../../schemas/user'); + /** * @api {post} /auth/register Register * @apiName Register @@ -15,17 +17,17 @@ const login = require('./login'); * * @apiSuccess {Array} Array Array of Note objects. */ -auth.post('/register', register); +auth.post('/register', UserSchema, register); /** - * @api {post} /auth/login Request JWT token + * @api {post} /auth/login Get access token * @apiName Login * @apiGroup Auth * * @apiParam {String} username username of the user. * @apiParam {String} password password of the user. * - * @apiSuccess {string} jwt_token JWT token. + * @apiSuccess {string} access_token Access token. */ auth.post('/login', login); diff --git a/app/routes/auth/login.js b/app/routes/auth/login.js index 74da097..1e40d51 100644 --- a/app/routes/auth/login.js +++ b/app/routes/auth/login.js @@ -1,5 +1,29 @@ -module.exports = (req, res) => { - const auth = []; +const mongoose = require('mongoose'); +const jwt = require('jsonwebtoken'); +const bcrypt = require('bcrypt-nodejs'); - res.status(200).json({ auth }); +module.exports = (req, res, next) => { + const User = mongoose.model('User'); + + User.findOne({ + username: req.body.username, + }, (err, user) => { + if (err) throw err; + + if (!user) { + next({ status: 400, message: 'Authentication failed. User not found.' }); + } else { + // check if password matches + const isMatch = bcrypt.compare(req.body.password, User.password); + if (isMatch && !err) { + // if user is found and password is right create a token + const token = 'test'; + // return the information including token as JSON + res.json({ success: true, access_token: `JWT ${token}` }); + } else { + next({ status: 401, message: 'Authentication failed. User not found.' }); + res.status(401).send({ success: false, msg: 'Authentication failed. Wrong password.' }); + } + } + }); }; diff --git a/app/routes/auth/register.js b/app/routes/auth/register.js index 74da097..0025e93 100644 --- a/app/routes/auth/register.js +++ b/app/routes/auth/register.js @@ -1,5 +1,29 @@ -module.exports = (req, res) => { - const auth = []; +const mongoose = require('mongoose'); +const bcrypt = require('bcrypt-nodejs'); - res.status(200).json({ auth }); +module.exports = (req, res, next) => { + const UserModel = mongoose.model('User'); + + const passwordHash = bcrypt.hashSync(req.body.password); + + const User = new UserModel({ + firstname: req.body.firstname, + lastname: req.body.lastname, + username: req.body.username, + password: passwordHash, + }); + + UserModel.findOne({ + username: req.body.username, + }, (err, user) => { + next({ status: 401, message: 'Username is already taken.' }); + }); + + return User.save((saveErr) => { + if (saveErr) { + return next({ status: 500, message: 'Database error', error: [] }); + } + + return res.status(200).json(User); + }); }; From 80a57fc7211df254c923930a4d43bfe57a6be88c Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:15:31 +0100 Subject: [PATCH 22/27] Note routes --- app/routes/note/all.js | 12 ------------ app/routes/note/delete.js | 19 ++++++++++--------- app/routes/note/index.js | 22 ++++++---------------- app/routes/note/single.js | 8 +++++++- app/routes/note/update.js | 31 ++++++++++++++++++++++--------- 5 files changed, 45 insertions(+), 47 deletions(-) delete mode 100644 app/routes/note/all.js diff --git a/app/routes/note/all.js b/app/routes/note/all.js deleted file mode 100644 index a64ac2c..0000000 --- a/app/routes/note/all.js +++ /dev/null @@ -1,12 +0,0 @@ -const mongoose = require('mongoose'); - -module.exports = (req, res) => { - const NoteModel = mongoose.model('Note'); - - NoteModel.find({}) - .lean() - .exec() - .then((result) => { - res.status(200).json(result); - }); -}; diff --git a/app/routes/note/delete.js b/app/routes/note/delete.js index 68fe7d2..73afb4f 100644 --- a/app/routes/note/delete.js +++ b/app/routes/note/delete.js @@ -6,13 +6,14 @@ const mongoose = require('mongoose'); module.exports = (req, res) => { const NoteModel = mongoose.model('Note'); - NoteModel.findByIdAndDelete(req.params.id) - .lean() - .exec() - .then(() => { - res.status(200).json({ success: true, msg: 'Note deleted.' }); - }) - .catch(() => { - res.status(404).json({ success: false, msg: 'Note does not exists.' }); - }); + NoteModel.findOneAndDelete({ _id: req.params.id }, (err, note) => { + if (err) return res.status(500).send(err); + if (!note) return res.status(404).json({ message: 'Note does not exists.' }); + + const response = { + message: 'Note successfully deleted', + }; + + return res.status(200).send(response); + }); }; diff --git a/app/routes/note/index.js b/app/routes/note/index.js index dbdf13e..b857d60 100644 --- a/app/routes/note/index.js +++ b/app/routes/note/index.js @@ -1,26 +1,16 @@ const note = require('express').Router(); -const all = require('./all'); const single = require('./single'); const create = require('./create'); const update = require('./update'); const remove = require('./delete'); /** - * @api {get} /note Request all notes + * @api {get} /note/:id Get note * @apiName GetNotes * @apiGroup Note * - * @apiSuccess {Array} Array Array of Note objects. - */ -note.get('/', all); - -/** - * @api {get} /note/:id Request Note information - * @apiName GetNotes - * @apiGroup Note - * - * @apiParam {Number} id Notes unique ID. + * @apiParam {String} id Note unique ID. * * @apiSuccess {string} title Title of the note. * @apiSuccess {string} text Text of the note. @@ -37,20 +27,20 @@ note.get('/:id', single); note.post('/', create); /** - * @api {delete} /note/:id Delete a note + * @api {delete} /note/:id Delete note * @apiName DeleteNote * @apiGroup Note * - * @apiParam {Number} id Note id. + * @apiParam {String} id Note unique ID. */ note.delete('/:id', remove); /** - * @api {put} /note/:id Update a note + * @api {put} /note/:id Update note * @apiName UpdateNote * @apiGroup Note * - * @apiParam {Number} id Note id. + * @apiParam {String} id Note unique ID. * * @apiSuccess {Object} Object Updated note. */ diff --git a/app/routes/note/single.js b/app/routes/note/single.js index 5be1fa8..32701c1 100644 --- a/app/routes/note/single.js +++ b/app/routes/note/single.js @@ -1,12 +1,18 @@ const mongoose = require('mongoose'); +// TODO: verify owner + module.exports = (req, res) => { const NoteModel = mongoose.model('Note'); - NoteModel.find({ _id: req.params.id }) + NoteModel.findOne({ _id: req.params.id }) .lean() .exec() .then((result) => { + if (result === null) { + res.status(404).json({ success: false, msg: 'Note does not exists.' }); + } + res.status(200).json(result); }) .catch(() => { diff --git a/app/routes/note/update.js b/app/routes/note/update.js index 5be1fa8..fa7f85d 100644 --- a/app/routes/note/update.js +++ b/app/routes/note/update.js @@ -1,15 +1,28 @@ const mongoose = require('mongoose'); +// TODO: verify auth +// TODO: verify owner + module.exports = (req, res) => { const NoteModel = mongoose.model('Note'); - NoteModel.find({ _id: req.params.id }) - .lean() - .exec() - .then((result) => { - res.status(200).json(result); - }) - .catch(() => { - res.status(404).json({ success: false, msg: 'Note does not exists.' }); - }); + NoteModel.findOneAndUpdate( + // the id of the item to find + { _id: req.params.id }, + + // the change to be made. Mongoose will smartly combine your existing + // document with this change, which allows for partial updates too + req.body, + + // an option that asks mongoose to return the updated version + // of the document instead of the pre-updated one. + { new: true }, + + // the callback function + (err, note) => { + // Handle any possible database errors + if (err) return res.status(500).send(err); + return res.json(note); + }, + ); }; From 15fee6c83d187ce1b6c517e030331922133ea1d5 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:15:42 +0100 Subject: [PATCH 23/27] User routes --- app/routes/user/all.js | 11 ------ app/routes/user/create.js | 12 ------- app/routes/user/delete.js | 5 +++ app/routes/user/index.js | 71 ++++++++++----------------------------- app/routes/user/notes.js | 0 app/routes/user/single.js | 5 --- app/routes/user/update.js | 5 +++ 7 files changed, 27 insertions(+), 82 deletions(-) delete mode 100644 app/routes/user/all.js delete mode 100644 app/routes/user/create.js create mode 100644 app/routes/user/notes.js delete mode 100644 app/routes/user/single.js diff --git a/app/routes/user/all.js b/app/routes/user/all.js deleted file mode 100644 index 9e1d309..0000000 --- a/app/routes/user/all.js +++ /dev/null @@ -1,11 +0,0 @@ -const mongoose = require('mongoose'); - -module.exports = (req, res) => { - const UserModel = mongoose.model('User'); - const users = UserModel.find() - .lean() - .exec() - .then(() => { - res.status(200).json(users); - }); -}; diff --git a/app/routes/user/create.js b/app/routes/user/create.js deleted file mode 100644 index 7098f3c..0000000 --- a/app/routes/user/create.js +++ /dev/null @@ -1,12 +0,0 @@ -const Joi = require('joi'); -// const jwt = require('jsonwebtoken'); -// const bcrypt = require('bcrypt-nodejs'); - -const schema = Joi.object().keys({ - firstname: Joi.string().alphanum().min(2), - lastname: Joi.string().alphanum().min(2), - username: Joi.string().alphanum().min(3).max(30) - .required(), - password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/), - access_token: [Joi.string(), Joi.number()], -}).with('username').without('password', 'access_token'); diff --git a/app/routes/user/delete.js b/app/routes/user/delete.js index e69de29..0e97c8b 100644 --- a/app/routes/user/delete.js +++ b/app/routes/user/delete.js @@ -0,0 +1,5 @@ +module.exports = (req, res) => { + const user = {}; + + res.status(200).json({ user }); +}; diff --git a/app/routes/user/index.js b/app/routes/user/index.js index f80dee0..0f5d429 100644 --- a/app/routes/user/index.js +++ b/app/routes/user/index.js @@ -1,38 +1,12 @@ const user = require('express').Router(); -const all = require('./all'); const profile = require('./profile'); -const single = require('./single'); -// const create = require('./create'); -// const update = require('./update'); -// const remove = require('./delete'); +const update = require('./update'); +const remove = require('./delete'); +// const notes = require('./notes'); /** - * @api {get} /user Request all Users information - * @apiName GetUsers - * @apiGroup User - * - * @apiParam {Number} id Users unique ID. - * - * @apiSuccess {Array} Array User objects. - */ -user.get('/', all); - -/** - * @api {get} /user/:id Request User information - * @apiName GetUser - * @apiGroup User - * - * @apiParam {Number} id Users unique ID. - * - * @apiSuccess {String} firstname Firstname of the User. - * @apiSuccess {String} lastname Lastname of the User. - * @apiSuccess {String} username Username of the User. - */ -user.get('/:userId', single); - -/** - * @api {get} /user/me Request current account information + * @api {get} /user/me Get user information * @apiName GetUser * @apiGroup User * @@ -43,39 +17,28 @@ user.get('/:userId', single); user.get('/me', profile); /** - * @api {put} /user/me Update current account information - * @apiName UpdateUser - * @apiGroup User - * - * @apiParam {String} firstname Firstname of the User. - * @apiParam {String} lastname Lastname of the User. - * @apiParam {String} username Username of the User. - */ -user.put('/me', profile); + * @api {put} /user/me Update account information + * @apiName UpdateUser + * @apiGroup User + * + * @apiSuccess {Object} user User object. + */ +user.put('/me', update); /** - * @api {delete} /user/me Delete current account + * @api {delete} /user/me Delete account * @apiName DeleteUser * @apiGroup User - * - * @apiParam {String} firstname Firstname of the User. - * @apiParam {String} lastname Lastname of the User. - * @apiParam {String} username Username of the User. */ -user.delete('/me', profile); +user.delete('/me', remove); /** - * @api {get} /user/me/notes Get notes created by this account - * @apiName GetNotes - * @apiGroup User,Note + * @api {get} /user/me/notes Get all notes + * @apiName GetNotesByUserId + * @apiGroup User notes * - * @apiSuccess {string} title Title of the note. - * @apiSuccess {string} text Text of the note. + * @apiSuccess {Array} Array Notes of the user. */ user.get('/me/notes', profile); -// user.post('/', create) -// user.put('/:userId', update) -// user.delete('/:userId', remove) - module.exports = user; diff --git a/app/routes/user/notes.js b/app/routes/user/notes.js new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/user/single.js b/app/routes/user/single.js deleted file mode 100644 index fda0e54..0000000 --- a/app/routes/user/single.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = (req, res) => { - const user = req.model; - - res.status(200).json({ user }); -}; diff --git a/app/routes/user/update.js b/app/routes/user/update.js index e69de29..0e97c8b 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -0,0 +1,5 @@ +module.exports = (req, res) => { + const user = {}; + + res.status(200).json({ user }); +}; From 72bc53b6a4b58741d21c99a7906c6add20fe8cc1 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:15:53 +0100 Subject: [PATCH 24/27] User model --- app/models/user.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/user.js b/app/models/user.js index e0bbbe5..4f8b98b 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -12,7 +12,9 @@ const UserSchema = new Schema({ username: { type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/^[a-zA-Z0-9]+$/, 'is invalid'], index: true, }, - password: String, + password: { + type: String, required: [true, "can't be blank"], + }, }, { timestamps: true }); module.exports = UserSchema; From c9b9ee5d3fe802628669f1a83396f515c4d322b3 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:16:00 +0100 Subject: [PATCH 25/27] Docs --- docs/api_data.js | 236 ++++++++++++------------------------------ docs/api_data.json | 236 ++++++++++++------------------------------ docs/api_project.js | 2 +- docs/api_project.json | 2 +- 4 files changed, 130 insertions(+), 346 deletions(-) diff --git a/docs/api_data.js b/docs/api_data.js index 6f0166d..6b70267 100644 --- a/docs/api_data.js +++ b/docs/api_data.js @@ -2,7 +2,7 @@ define({ "api": [ { "type": "post", "url": "/auth/login", - "title": "Request JWT token", + "title": "Get access token", "name": "Login", "group": "Auth", "parameter": { @@ -32,7 +32,7 @@ define({ "api": [ "group": "Success 200", "type": "string", "optional": false, - "field": "jwt", + "field": "jwt_token", "description": "

JWT token.

" } ] @@ -125,28 +125,18 @@ define({ "api": [ { "type": "delete", "url": "/note/:id", - "title": "Delete a note", + "title": "Delete note", "name": "DeleteNote", "group": "Note", - "version": "0.0.0", - "filename": "app/routes/note/index.js", - "groupTitle": "Note" - }, - { - "type": "get", - "url": "/note", - "title": "Request all notes", - "name": "GetNotes", - "group": "Note", - "success": { + "parameter": { "fields": { - "Success 200": [ + "Parameter": [ { - "group": "Success 200", - "type": "Array", + "group": "Parameter", + "type": "String", "optional": false, - "field": "Array", - "description": "

Array of Note objects.

" + "field": "id", + "description": "

Note unique ID.

" } ] } @@ -158,7 +148,7 @@ define({ "api": [ { "type": "get", "url": "/note/:id", - "title": "Request Note information", + "title": "Get note", "name": "GetNotes", "group": "Note", "parameter": { @@ -166,10 +156,10 @@ define({ "api": [ "Parameter": [ { "group": "Parameter", - "type": "Number", + "type": "String", "optional": false, "field": "id", - "description": "

Notes unique ID.

" + "description": "

Note unique ID.

" } ] } @@ -198,89 +188,48 @@ define({ "api": [ "filename": "app/routes/note/index.js", "groupTitle": "Note" }, + { + "type": "put", + "url": "/note/:id", + "title": "Update note", + "name": "UpdateNote", + "group": "Note", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "id", + "description": "

Note unique ID.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Object", + "optional": false, + "field": "Object", + "description": "

Updated note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, { "type": "delete", "url": "/user/me", - "title": "Delete current account", + "title": "Delete account", "name": "DeleteUser", "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" - } - ] - } - }, - "version": "0.0.0", - "filename": "app/routes/user/index.js", - "groupTitle": "User" - }, - { - "type": "get", - "url": "/user/:id", - "title": "Request User information", - "name": "GetUser", - "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "Number", - "optional": false, - "field": "id", - "description": "

Users unique ID.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" - } - ] - } - }, "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" @@ -288,7 +237,7 @@ define({ "api": [ { "type": "get", "url": "/user/me", - "title": "Request current account information", + "title": "Get user information", "name": "GetUser", "group": "User", "success": { @@ -322,71 +271,21 @@ define({ "api": [ "filename": "app/routes/user/index.js", "groupTitle": "User" }, - { - "type": "get", - "url": "/user", - "title": "Request all Users information", - "name": "GetUsers", - "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "Number", - "optional": false, - "field": "id", - "description": "

Users unique ID.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "Array", - "optional": false, - "field": "Array", - "description": "

User objects.

" - } - ] - } - }, - "version": "0.0.0", - "filename": "app/routes/user/index.js", - "groupTitle": "User" - }, { "type": "put", "url": "/user/me", - "title": "Update current account information", + "title": "Update account information", "name": "UpdateUser", "group": "User", - "parameter": { + "success": { "fields": { - "Parameter": [ + "Success 200": [ { - "group": "Parameter", - "type": "String", + "group": "Success 200", + "type": "Object", "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" + "field": "user", + "description": "

User object.

" } ] } @@ -398,31 +297,24 @@ define({ "api": [ { "type": "get", "url": "/user/me/notes", - "title": "Get notes created by this account", - "name": "GetNotes", - "group": "User_Note", + "title": "Get all notes", + "name": "GetNotesByUserId", + "group": "User_notes", "success": { "fields": { "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "Array", "optional": false, - "field": "title", - "description": "

Title of the note.

" - }, - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "text", - "description": "

Text of the note.

" + "field": "Array", + "description": "

Notes of the user.

" } ] } }, "version": "0.0.0", "filename": "app/routes/user/index.js", - "groupTitle": "User_Note" + "groupTitle": "User_notes" } ] }); diff --git a/docs/api_data.json b/docs/api_data.json index da25f47..0c657a3 100644 --- a/docs/api_data.json +++ b/docs/api_data.json @@ -2,7 +2,7 @@ { "type": "post", "url": "/auth/login", - "title": "Request JWT token", + "title": "Get access token", "name": "Login", "group": "Auth", "parameter": { @@ -32,7 +32,7 @@ "group": "Success 200", "type": "string", "optional": false, - "field": "jwt", + "field": "jwt_token", "description": "

JWT token.

" } ] @@ -125,28 +125,18 @@ { "type": "delete", "url": "/note/:id", - "title": "Delete a note", + "title": "Delete note", "name": "DeleteNote", "group": "Note", - "version": "0.0.0", - "filename": "app/routes/note/index.js", - "groupTitle": "Note" - }, - { - "type": "get", - "url": "/note", - "title": "Request all notes", - "name": "GetNotes", - "group": "Note", - "success": { + "parameter": { "fields": { - "Success 200": [ + "Parameter": [ { - "group": "Success 200", - "type": "Array", + "group": "Parameter", + "type": "String", "optional": false, - "field": "Array", - "description": "

Array of Note objects.

" + "field": "id", + "description": "

Note unique ID.

" } ] } @@ -158,7 +148,7 @@ { "type": "get", "url": "/note/:id", - "title": "Request Note information", + "title": "Get note", "name": "GetNotes", "group": "Note", "parameter": { @@ -166,10 +156,10 @@ "Parameter": [ { "group": "Parameter", - "type": "Number", + "type": "String", "optional": false, "field": "id", - "description": "

Notes unique ID.

" + "description": "

Note unique ID.

" } ] } @@ -198,89 +188,48 @@ "filename": "app/routes/note/index.js", "groupTitle": "Note" }, + { + "type": "put", + "url": "/note/:id", + "title": "Update note", + "name": "UpdateNote", + "group": "Note", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "id", + "description": "

Note unique ID.

" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "Object", + "optional": false, + "field": "Object", + "description": "

Updated note.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/note/index.js", + "groupTitle": "Note" + }, { "type": "delete", "url": "/user/me", - "title": "Delete current account", + "title": "Delete account", "name": "DeleteUser", "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" - } - ] - } - }, - "version": "0.0.0", - "filename": "app/routes/user/index.js", - "groupTitle": "User" - }, - { - "type": "get", - "url": "/user/:id", - "title": "Request User information", - "name": "GetUser", - "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "Number", - "optional": false, - "field": "id", - "description": "

Users unique ID.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" - } - ] - } - }, "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" @@ -288,7 +237,7 @@ { "type": "get", "url": "/user/me", - "title": "Request current account information", + "title": "Get user information", "name": "GetUser", "group": "User", "success": { @@ -322,71 +271,21 @@ "filename": "app/routes/user/index.js", "groupTitle": "User" }, - { - "type": "get", - "url": "/user", - "title": "Request all Users information", - "name": "GetUsers", - "group": "User", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "Number", - "optional": false, - "field": "id", - "description": "

Users unique ID.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "Array", - "optional": false, - "field": "Array", - "description": "

User objects.

" - } - ] - } - }, - "version": "0.0.0", - "filename": "app/routes/user/index.js", - "groupTitle": "User" - }, { "type": "put", "url": "/user/me", - "title": "Update current account information", + "title": "Update account information", "name": "UpdateUser", "group": "User", - "parameter": { + "success": { "fields": { - "Parameter": [ + "Success 200": [ { - "group": "Parameter", - "type": "String", + "group": "Success 200", + "type": "Object", "optional": false, - "field": "firstname", - "description": "

Firstname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "lastname", - "description": "

Lastname of the User.

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "username", - "description": "

Username of the User.

" + "field": "user", + "description": "

User object.

" } ] } @@ -398,31 +297,24 @@ { "type": "get", "url": "/user/me/notes", - "title": "Get notes created by this account", - "name": "GetNotes", - "group": "User_Note", + "title": "Get all notes", + "name": "GetNotesByUserId", + "group": "User_notes", "success": { "fields": { "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "Array", "optional": false, - "field": "title", - "description": "

Title of the note.

" - }, - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "text", - "description": "

Text of the note.

" + "field": "Array", + "description": "

Notes of the user.

" } ] } }, "version": "0.0.0", "filename": "app/routes/user/index.js", - "groupTitle": "User_Note" + "groupTitle": "User_notes" } ] diff --git a/docs/api_project.js b/docs/api_project.js index a71dc02..9efd796 100644 --- a/docs/api_project.js +++ b/docs/api_project.js @@ -8,7 +8,7 @@ define({ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2018-11-12T17:15:53.319Z", + "time": "2018-11-14T16:18:06.827Z", "url": "http://apidocjs.com", "version": "0.17.7" } diff --git a/docs/api_project.json b/docs/api_project.json index 96d6d09..2d6ea5e 100644 --- a/docs/api_project.json +++ b/docs/api_project.json @@ -8,7 +8,7 @@ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2018-11-12T17:15:53.319Z", + "time": "2018-11-14T16:18:06.827Z", "url": "http://apidocjs.com", "version": "0.17.7" } From bd8d95a8b44ec7d468a0f0b891344516debda69f Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:16:16 +0100 Subject: [PATCH 26/27] Test script --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 17bcd24..2d33447 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "title": "Mooc API" }, "scripts": { - "doc": "apidoc -i ./app/routes -o ./docs", - "test": "eslint ./" + "docs": "apidoc -i ./app/routes -o ./docs", + "test": "eslint ./ && npm run docs" }, "repository": { "type": "git", From 0b1361263ea363227cf8b6b5f3055d19b7f1e0ec Mon Sep 17 00:00:00 2001 From: sundowndev Date: Wed, 14 Nov 2018 18:16:33 +0100 Subject: [PATCH 27/27] Error handling middleware --- index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.js b/index.js index ff252bf..559c3ab 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,10 @@ const port = process.env.PORT || 8080; // set our port app.use('/', routes); +app.use((err, req, res, next) => { + res.status(err.status || 400).json({ success: false, message: err.message || 'An error occured.', errors: err.error || [] }); +}); + app.use((req, res) => { res.status(404).json({ message: 'Resource not found.' }); });