From 9d8c517b8264858e4333f6c644ccfc2f328b416c Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 12:28:37 +0100 Subject: [PATCH 01/18] Fix Eslint errors --- .eslintrc.json | 7 +++++-- app/models/user.js | 6 +++++- app/routes/auth/login.js | 16 +++++++++++++--- app/routes/auth/register.js | 11 +++++++++-- app/routes/note/create.js | 6 +++++- app/routes/note/index.js | 2 +- app/routes/user/index.js | 9 ++++++--- app/routes/user/update.js | 21 ++++++++++++++++++--- app/validation/auth.js | 2 +- app/validation/login.js | 6 +++++- app/validation/note/create.js | 6 +++++- app/validation/note/update.js | 6 +++++- app/validation/register.js | 6 +++++- index.js | 6 +++++- 14 files changed, 88 insertions(+), 22 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 6f67564..d3d9bfc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": "airbnb-base" -} \ No newline at end of file + "extends": "airbnb-base", + "rules": { + "max-len": ["error", { "comments": 120 }] + } +} diff --git a/app/models/user.js b/app/models/user.js index f176304..a71ea49 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -10,7 +10,11 @@ const UserSchema = new Schema({ type: String, required: [true, "can't be blank"], }, email: { - type: String, lowercase: true, unique: true, required: [true, "can't be blank"], index: true, + type: String, + lowercase: true, + unique: true, + required: [true, "can't be blank"], + index: true, }, password: { type: String, required: [true, "can't be blank"], diff --git a/app/routes/auth/login.js b/app/routes/auth/login.js index bff4b7c..76f303f 100644 --- a/app/routes/auth/login.js +++ b/app/routes/auth/login.js @@ -13,7 +13,10 @@ module.exports = (req, res, next) => { if (err) throw err; if (!user) { - return next({ status: 400, message: 'Authentication failed. User not found.' }); + return next({ + status: 400, + message: 'Authentication failed. User not found.', + }); } // check if password matches @@ -25,7 +28,11 @@ module.exports = (req, res, next) => { email: user.email, }; - const token = jwt.sign({ user: dataUser }, secret, { expiresIn: '12h' }); + const token = jwt.sign({ + user: dataUser, + }, secret, { + expiresIn: '12h', + }); // return the information including token as JSON return res.json({ @@ -40,7 +47,10 @@ module.exports = (req, res, next) => { }); } - return next({ status: 401, message: 'Authentication failed. Wrong password.' }); + return next({ + status: 401, + message: 'Authentication failed. Wrong password.', + }); }); }); }; diff --git a/app/routes/auth/register.js b/app/routes/auth/register.js index aaa4f02..567116e 100644 --- a/app/routes/auth/register.js +++ b/app/routes/auth/register.js @@ -15,12 +15,19 @@ module.exports = (req, res, next) => { UserModel.countDocuments({ email: req.body.email }, (err, c) => { if (c !== 0) { - return next({ status: 401, message: 'Email is already taken by another user.' }); + return next({ + status: 401, + message: 'Email is already taken by another user.', + }); } return User.save((saveErr) => { if (saveErr) { - return next({ status: 500, message: 'Database error', error: [saveErr] }); + return next({ + status: 500, + message: 'Database error', + error: [saveErr], + }); } return res.status(201).json({ success: true, message: 'Success' }); diff --git a/app/routes/note/create.js b/app/routes/note/create.js index c7b331e..51127af 100644 --- a/app/routes/note/create.js +++ b/app/routes/note/create.js @@ -6,7 +6,11 @@ module.exports = (req, res, next) => { const { user } = jwt.decode(req.headers.authorization); - const Note = new NoteModel({ title: req.body.title, text: req.body.text, user: user.id }); + const Note = new NoteModel({ + title: req.body.title, + text: req.body.text, + user: user.id, + }); Note.save((err) => { if (err) { diff --git a/app/routes/note/index.js b/app/routes/note/index.js index d40119c..3de1348 100644 --- a/app/routes/note/index.js +++ b/app/routes/note/index.js @@ -58,7 +58,7 @@ note.put('/:id', Authentication, UpdateValidation, update); * "message": "Note successfully deleted." * } * @apiErrorExample {json} Error-Response: - * HTTP/1.1 403 Not Found + * HTTP/1.1 403 Forbidden * { * "success": false, * "message": "Access forbidden.", diff --git a/app/routes/user/index.js b/app/routes/user/index.js index 42ffe60..a245680 100644 --- a/app/routes/user/index.js +++ b/app/routes/user/index.js @@ -22,10 +22,13 @@ user.get('/me', Authentication, profile); * @api {put} /user/me Update account information * @apiName UpdateUser * @apiGroup User + * @apiDescription Send only password and new_password to change the password. Otherwise they will be ignored. * - * @apiParam {String} Firstname new firstname. - * @apiParam {String} Lastname new lastname. - * @apiParam {String} Email new email address. + * @apiParam {String} Firstname New firstname. + * @apiParam {String} Lastname New lastname. + * @apiParam {String} Email New email address. + * @apiParam {String} Password Actual password. + * @apiParam {String} Password New password. * * @apiSuccess {Object} user User object. */ diff --git a/app/routes/user/update.js b/app/routes/user/update.js index 0e97c8b..66c0e4b 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -1,5 +1,20 @@ -module.exports = (req, res) => { - const user = {}; +const mongoose = require('mongoose'); +const jwt = require('jsonwebtoken'); - res.status(200).json({ user }); +module.exports = (req, res, next) => { + const UserModel = mongoose.model('User'); + + const { user } = jwt.decode(req.headers.authorization); + + return UserModel.findById(user.id, 'id firstname lastname email') + .lean() + .exec() + .then((result) => { + if (result === null) { + return next({ status: 401, message: 'User does not exists.' }); + } + + return res.status(200).json(result); + }) + .catch(() => next({ status: 401, message: 'User does not exists.' })); }; diff --git a/app/validation/auth.js b/app/validation/auth.js index 924c154..5d52846 100644 --- a/app/validation/auth.js +++ b/app/validation/auth.js @@ -16,7 +16,7 @@ module.exports = (req, res, next) => { return next({ status: 401, error: validateErr.details }); } - return jwt.verify(req.headers.authorization, secret, (err, decoded) => { + return jwt.verify(req.headers.authorization, secret, (err) => { if (err) { return next({ status: 401, message: 'Token error.', error: [err] }); } diff --git a/app/validation/login.js b/app/validation/login.js index 0147335..b0850a7 100644 --- a/app/validation/login.js +++ b/app/validation/login.js @@ -12,7 +12,11 @@ module.exports = (req, res, next) => { }, schema, (validateErr) => { if (validateErr) { - return next({ status: 400, message: 'Form is invalid.', error: validateErr.details }); + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); } return next(); diff --git a/app/validation/note/create.js b/app/validation/note/create.js index 2610694..09be690 100644 --- a/app/validation/note/create.js +++ b/app/validation/note/create.js @@ -12,7 +12,11 @@ module.exports = (req, res, next) => { }, schema, (validateErr) => { if (validateErr) { - return next({ status: 400, message: 'Form is invalid.', error: validateErr.details }); + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); } return next(); diff --git a/app/validation/note/update.js b/app/validation/note/update.js index 33d584c..385d731 100644 --- a/app/validation/note/update.js +++ b/app/validation/note/update.js @@ -12,7 +12,11 @@ module.exports = (req, res, next) => { }, schema, (validateErr) => { if (validateErr) { - return next({ status: 400, message: 'Form is invalid.', error: validateErr.details }); + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); } return next(); diff --git a/app/validation/register.js b/app/validation/register.js index 9db7087..c148ad6 100644 --- a/app/validation/register.js +++ b/app/validation/register.js @@ -16,7 +16,11 @@ module.exports = (req, res, next) => { }, schema, (validateErr) => { if (validateErr) { - return next({ status: 400, message: 'Form is invalid.', error: validateErr.details }); + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); } return next(); diff --git a/index.js b/index.js index 9ce0d18..57f04cf 100644 --- a/index.js +++ b/index.js @@ -10,7 +10,11 @@ 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 || [] }); + res.status(err.status || 400).json({ + success: false, + message: err.message || 'An error occured.', + errors: err.error || [], + }); }); app.use((req, res) => { From e9a2da4bd8e439de2be43909e36e9f693801fe74 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 12:28:58 +0100 Subject: [PATCH 02/18] API Docs --- docs/api_data.js | 69 +++++++++++++++++++++++++++++++++++++++---- docs/api_data.json | 69 +++++++++++++++++++++++++++++++++++++++---- docs/api_project.js | 2 +- docs/api_project.json | 2 +- 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/docs/api_data.js b/docs/api_data.js index e884f89..53600a1 100644 --- a/docs/api_data.js +++ b/docs/api_data.js @@ -12,8 +12,8 @@ define({ "api": [ "group": "Parameter", "type": "String", "optional": false, - "field": "username", - "description": "

username of the user.

" + "field": "email", + "description": "

email of the user.

" }, { "group": "Parameter", @@ -69,8 +69,8 @@ define({ "api": [ "group": "Parameter", "type": "String", "optional": false, - "field": "username", - "description": "

username of the user.

" + "field": "email", + "description": "

email of the user.

" }, { "group": "Parameter", @@ -99,6 +99,36 @@ define({ "api": [ "filename": "app/routes/auth/index.js", "groupTitle": "Auth" }, + { + "type": "post", + "url": "/auth/reset-password", + "title": "Reset password", + "name": "ResetPass", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "email", + "description": "

email of the user.

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

password of the user.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, { "type": "post", "url": "/note", @@ -157,7 +187,7 @@ define({ "api": [ "examples": [ { "title": "Error-Response:", - "content": "HTTP/1.1 403 Not Found\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}", + "content": "HTTP/1.1 403 Forbidden\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}", "type": "json" } ] @@ -278,7 +308,7 @@ define({ "api": [ { "type": "get", "url": "/user/me", - "title": "Get user information", + "title": "Get account information", "name": "GetUser", "group": "User", "success": { @@ -318,6 +348,33 @@ define({ "api": [ "title": "Update account information", "name": "UpdateUser", "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "Firstname", + "description": "

new firstname.

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

new lastname.

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

new email address.

" + } + ] + } + }, "success": { "fields": { "Success 200": [ diff --git a/docs/api_data.json b/docs/api_data.json index 16d22ec..4ee18b9 100644 --- a/docs/api_data.json +++ b/docs/api_data.json @@ -12,8 +12,8 @@ "group": "Parameter", "type": "String", "optional": false, - "field": "username", - "description": "

username of the user.

" + "field": "email", + "description": "

email of the user.

" }, { "group": "Parameter", @@ -69,8 +69,8 @@ "group": "Parameter", "type": "String", "optional": false, - "field": "username", - "description": "

username of the user.

" + "field": "email", + "description": "

email of the user.

" }, { "group": "Parameter", @@ -99,6 +99,36 @@ "filename": "app/routes/auth/index.js", "groupTitle": "Auth" }, + { + "type": "post", + "url": "/auth/reset-password", + "title": "Reset password", + "name": "ResetPass", + "group": "Auth", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "email", + "description": "

email of the user.

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

password of the user.

" + } + ] + } + }, + "version": "0.0.0", + "filename": "app/routes/auth/index.js", + "groupTitle": "Auth" + }, { "type": "post", "url": "/note", @@ -157,7 +187,7 @@ "examples": [ { "title": "Error-Response:", - "content": "HTTP/1.1 403 Not Found\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}", + "content": "HTTP/1.1 403 Forbidden\n{\n \"success\": false,\n \"message\": \"Access forbidden.\",\n \"errors\": []\n}", "type": "json" } ] @@ -278,7 +308,7 @@ { "type": "get", "url": "/user/me", - "title": "Get user information", + "title": "Get account information", "name": "GetUser", "group": "User", "success": { @@ -318,6 +348,33 @@ "title": "Update account information", "name": "UpdateUser", "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "Firstname", + "description": "

new firstname.

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

new lastname.

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

new email address.

" + } + ] + } + }, "success": { "fields": { "Success 200": [ diff --git a/docs/api_project.js b/docs/api_project.js index c53faf1..3f62ab3 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-15T18:00:50.902Z", + "time": "2018-11-16T10:11:39.561Z", "url": "http://apidocjs.com", "version": "0.17.7" } diff --git a/docs/api_project.json b/docs/api_project.json index 4af392b..bf2c8b6 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-15T18:00:50.902Z", + "time": "2018-11-16T10:11:39.561Z", "url": "http://apidocjs.com", "version": "0.17.7" } From a6cdbed50dc805dae36c170d1259676c5c6001f2 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 16:43:01 +0100 Subject: [PATCH 03/18] [Fix #3] Delete account --- app/routes/user/delete.js | 43 ++++++++++++++++++++++++++++++++--- app/validation/user/delete.js | 22 ++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 app/validation/user/delete.js diff --git a/app/routes/user/delete.js b/app/routes/user/delete.js index 0e97c8b..8eeefeb 100644 --- a/app/routes/user/delete.js +++ b/app/routes/user/delete.js @@ -1,5 +1,42 @@ -module.exports = (req, res) => { - const user = {}; +const mongoose = require('mongoose'); +const jwt = require('jsonwebtoken'); +const bcrypt = require('bcrypt-nodejs'); - res.status(200).json({ user }); +module.exports = (req, res, next) => { + const UserModel = mongoose.model('User'); + + const { user } = jwt.decode(req.headers.authorization); + + return UserModel.findOne({ _id: user.id }) + .lean() + .exec() + .then((User) => { + if (User === null) { + return next({ status: 404, message: 'User does not exists.' }); + } + + return bcrypt.compare( + req.body.password, + User.password, + (error, result) => { + if (!result || error) { + return next({ + status: 401, + message: 'Authentication failed. Wrong password.', + }); + } + + return UserModel.deleteOne({ _id: User._id }, (err) => { + if (err) { + return next({ status: 500 }); + } + + return res.status(204).json({ + success: true, + message: 'Account deleted.', + }); + }); + }, + ); + }); }; diff --git a/app/validation/user/delete.js b/app/validation/user/delete.js new file mode 100644 index 0000000..58becc1 --- /dev/null +++ b/app/validation/user/delete.js @@ -0,0 +1,22 @@ +const Joi = require('joi'); + +module.exports = (req, res, next) => { + const schema = Joi.object().keys({ + password: Joi.string().required(), + }); + + Joi.validate({ + password: req.body.password, + }, + schema, (validateErr) => { + if (validateErr) { + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); + } + + return next(); + }); +}; From ade50cb2487e90de65c5480622bc407b49351442 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 17:31:37 +0100 Subject: [PATCH 04/18] [Fix #5] Verify user exists in authentication middleware --- app/validation/auth/auth.js | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/validation/auth/auth.js diff --git a/app/validation/auth/auth.js b/app/validation/auth/auth.js new file mode 100644 index 0000000..2e6c002 --- /dev/null +++ b/app/validation/auth/auth.js @@ -0,0 +1,44 @@ +const Joi = require('joi'); +const jwt = require('jsonwebtoken'); +const mongoose = require('mongoose'); + +const secret = require.main.require('./config/secret'); + +module.exports = (req, res, next) => { + const UserModel = mongoose.model('User'); + + const schema = Joi.object().keys({ + access_token: Joi.string().required(), + }); + + Joi.validate({ + access_token: req.headers.authorization, + }, + schema, (validateErr) => { + if (validateErr) { + return next({ status: 401, error: validateErr.details }); + } + + return jwt.verify(req.headers.authorization, secret, (err, decoded) => { + if (err) { + return next({ status: 401, message: 'Token error.', error: [err] }); + } + + return UserModel.countDocuments( + { + _id: decoded.user.id, + }, (QueryError, count) => { + if (count !== 1) { + return next({ + status: 403, + message: 'Your session is invalid. Please try sign in again.', + error: [], + }); + } + + return next(); + }, + ); + }); + }); +}; From 1f9bca6641453d62350e5fb3b9770e7c131f2699 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 17:32:18 +0100 Subject: [PATCH 05/18] HTTP code --- app/validation/auth/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/validation/auth/auth.js b/app/validation/auth/auth.js index 2e6c002..1ff58b4 100644 --- a/app/validation/auth/auth.js +++ b/app/validation/auth/auth.js @@ -30,7 +30,7 @@ module.exports = (req, res, next) => { }, (QueryError, count) => { if (count !== 1) { return next({ - status: 403, + status: 401, message: 'Your session is invalid. Please try sign in again.', error: [], }); From af28952b3a595f1ccf1867c7f63932673b5a9e23 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:18:27 +0100 Subject: [PATCH 06/18] API docs --- docs/api_data.js | 54 ++++++++++++++++++++++++++++++++----------- docs/api_data.json | 54 ++++++++++++++++++++++++++++++++----------- docs/api_project.js | 2 +- docs/api_project.json | 2 +- 4 files changed, 84 insertions(+), 28 deletions(-) diff --git a/docs/api_data.js b/docs/api_data.js index 53600a1..caf1f12 100644 --- a/docs/api_data.js +++ b/docs/api_data.js @@ -30,7 +30,7 @@ define({ "api": [ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "access_token", "description": "

Access token.

" @@ -149,14 +149,14 @@ define({ "api": [ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -233,14 +233,14 @@ define({ "api": [ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -276,14 +276,14 @@ define({ "api": [ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -301,6 +301,19 @@ define({ "api": [ "title": "Delete account", "name": "DeleteUser", "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "Password", + "description": "

Account password.

" + } + ] + } + }, "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" @@ -348,6 +361,7 @@ define({ "api": [ "title": "Update account information", "name": "UpdateUser", "group": "User", + "description": "

Send only password and new_password to change the password. Otherwise they will be ignored.

", "parameter": { "fields": { "Parameter": [ @@ -355,22 +369,36 @@ define({ "api": [ "group": "Parameter", "type": "String", "optional": false, - "field": "Firstname", - "description": "

new firstname.

" + "field": "firstname", + "description": "

New firstname. (optional)

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

new lastname.

" + "field": "lastname", + "description": "

New lastname. (optional)

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

new email address.

" + "field": "email", + "description": "

New email address. (optional)

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

Actual password. (optional)

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

New password (only if you passed password parameter).

" } ] } diff --git a/docs/api_data.json b/docs/api_data.json index 4ee18b9..2ead4d6 100644 --- a/docs/api_data.json +++ b/docs/api_data.json @@ -30,7 +30,7 @@ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "access_token", "description": "

Access token.

" @@ -149,14 +149,14 @@ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -233,14 +233,14 @@ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -276,14 +276,14 @@ "Success 200": [ { "group": "Success 200", - "type": "string", + "type": "String", "optional": false, "field": "title", "description": "

Title of the note.

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

Text of the note.

" @@ -301,6 +301,19 @@ "title": "Delete account", "name": "DeleteUser", "group": "User", + "parameter": { + "fields": { + "Parameter": [ + { + "group": "Parameter", + "type": "String", + "optional": false, + "field": "Password", + "description": "

Account password.

" + } + ] + } + }, "version": "0.0.0", "filename": "app/routes/user/index.js", "groupTitle": "User" @@ -348,6 +361,7 @@ "title": "Update account information", "name": "UpdateUser", "group": "User", + "description": "

Send only password and new_password to change the password. Otherwise they will be ignored.

", "parameter": { "fields": { "Parameter": [ @@ -355,22 +369,36 @@ "group": "Parameter", "type": "String", "optional": false, - "field": "Firstname", - "description": "

new firstname.

" + "field": "firstname", + "description": "

New firstname. (optional)

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

new lastname.

" + "field": "lastname", + "description": "

New lastname. (optional)

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

new email address.

" + "field": "email", + "description": "

New email address. (optional)

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

Actual password. (optional)

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

New password (only if you passed password parameter).

" } ] } diff --git a/docs/api_project.js b/docs/api_project.js index 3f62ab3..63d3c23 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-16T10:11:39.561Z", + "time": "2018-11-16T14:21:42.357Z", "url": "http://apidocjs.com", "version": "0.17.7" } diff --git a/docs/api_project.json b/docs/api_project.json index bf2c8b6..c4a6d38 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-16T10:11:39.561Z", + "time": "2018-11-16T14:21:42.357Z", "url": "http://apidocjs.com", "version": "0.17.7" } From 51f2f495507fe6b546748dfecf7c6014d0514d18 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:18:37 +0100 Subject: [PATCH 07/18] Validation --- app/validation/auth.js | 27 ---------------------- app/validation/{ => auth}/login.js | 0 app/validation/{ => auth}/register.js | 0 app/validation/user/update.js | 33 +++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 27 deletions(-) delete mode 100644 app/validation/auth.js rename app/validation/{ => auth}/login.js (100%) rename app/validation/{ => auth}/register.js (100%) create mode 100644 app/validation/user/update.js diff --git a/app/validation/auth.js b/app/validation/auth.js deleted file mode 100644 index 5d52846..0000000 --- a/app/validation/auth.js +++ /dev/null @@ -1,27 +0,0 @@ -const Joi = require('joi'); -const jwt = require('jsonwebtoken'); - -const secret = require.main.require('./config/secret'); - -module.exports = (req, res, next) => { - const schema = Joi.object().keys({ - access_token: Joi.string().required(), - }); - - Joi.validate({ - access_token: req.headers.authorization, - }, - schema, (validateErr) => { - if (validateErr) { - return next({ status: 401, error: validateErr.details }); - } - - return jwt.verify(req.headers.authorization, secret, (err) => { - if (err) { - return next({ status: 401, message: 'Token error.', error: [err] }); - } - - return next(); - }); - }); -}; diff --git a/app/validation/login.js b/app/validation/auth/login.js similarity index 100% rename from app/validation/login.js rename to app/validation/auth/login.js diff --git a/app/validation/register.js b/app/validation/auth/register.js similarity index 100% rename from app/validation/register.js rename to app/validation/auth/register.js diff --git a/app/validation/user/update.js b/app/validation/user/update.js new file mode 100644 index 0000000..7b1c56c --- /dev/null +++ b/app/validation/user/update.js @@ -0,0 +1,33 @@ +const Joi = require('joi'); + +module.exports = (req, res, next) => { + const schema = Joi.object().keys({ + firstname: Joi.string().min(2), + lastname: Joi.string().min(2), + email: Joi.string().email({ minDomainAtoms: 2 }), + password: Joi.string(), + new_password: Joi.string(), + }).with('password', 'new_password') + .without('firstname', 'password') + .without('lastname', 'password') + .without('email', 'password'); + + Joi.validate({ + firstname: req.body.firstname, + lastname: req.body.lastname, + email: req.body.email, + password: req.body.password, + new_password: req.body.new_password, + }, + schema, (validateErr) => { + if (validateErr) { + return next({ + status: 400, + message: 'Form is invalid.', + error: validateErr.details, + }); + } + + return next(); + }); +}; From 81ede39ae97efc7d424bc3bf33488f0c22b20701 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:18:46 +0100 Subject: [PATCH 08/18] To do list --- todo.md | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/todo.md b/todo.md index b5edded..21ff1b2 100644 --- a/todo.md +++ b/todo.md @@ -2,11 +2,49 @@ ### Routes +- PUT /user/me (tous les champs sauf password) (200 ok avec en body le user après édition) - PUT /user/me (si tu vois password et new password, ou mets une autre route si tu veux) (200 ok avec le user après édition mais sans mot de passe bien sûr) -- DELETE /users/me (supprimer le profil) (204 no content, car le user est supprimé et tu ne me renvoi rien) - POST /auth/rester-password (email) (optionnel si tu te sens pas chaud) (200 ok) ### Other -- eslint test -- build test +- ESlint test + +## Specs + +**Pourvoir s'inscrire, se connecter, réinitialiser mot de passe (non connecté) :** + +- POST /auth/register (firstname, lastname, email, password) + (201 created) +- POST /auth/login (email, password) (200 ok avec en body le user et en header le token d'authentification) +- POST /auth/rester-password (email) (optionnel si tu te sens pas chaud) + (200 ok) + +**Pouvoir voir / modifier / supprimer son profil (connecté):** + +- PUT /user/me (tous les champs sauf password) (200 ok avec en body le user après édition) +- PUT /user/me (si tu vois password et new password, ou mets une autre route si tu veux) (200 ok avec le user après édition mais sans mot de passe bien sûr) +- DELETE /users/me (supprimer le profil) (204 no content, car le user est supprimé et tu ne me renvoi rien) +- GET /users/me (renvoi le user) (200 ok avec en body le user) pouvoir gérer les notes (connecté) + +**Notes:** + +- POST /notes (title optionnel, text optionnel, lié a user connecté) (201 creatred) +- PUT /notes/id (title optionnel, text optionnel) (200 ok avec en body la noté modifiée) +- DELETE /notes/id (supprimer la note) (204 no content) +- GET /user/me/ notes (toutes notes du user connecté) +- GET /notes/id (get la note de cet id si elle appartient au user connecté) + +**Finito ! C'est un crud avec un minimum de vérif qui sont :** + +- Est-ce que le user est connecté ou non +- Est-ce que le user est propriétaire de la ressource qu'il modifie ou supprime + +C'est tout ce qu'il y a besoin de vérifier. + +**Pour tout ce qui est erreur il n'y a que 4 règles à respecter :** + +- Pas le droit car pas connecté : 401 +- Pas le droit car connecté mais ne t'appartient pas : 403 +- Ressource n'existe pas : 404 +- Erreur de validation (si tu veux en faire) : 400 bad request From 0025e283342648697b06021a9c79d939fdeacdd0 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:20:25 +0100 Subject: [PATCH 09/18] Auth routes --- app/routes/auth/index.js | 6 +++--- app/routes/auth/login.js | 2 +- app/routes/auth/register.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/routes/auth/index.js b/app/routes/auth/index.js index a70e6fc..7055587 100644 --- a/app/routes/auth/index.js +++ b/app/routes/auth/index.js @@ -4,8 +4,8 @@ const register = require('./register'); const login = require('./login'); const reset = require('./reset'); -const RegisterValidation = require.main.require('./app/validation/register'); -const LoginValidation = require.main.require('./app/validation/login'); +const RegisterValidation = require.main.require('./app/validation/auth/register'); +const LoginValidation = require.main.require('./app/validation/auth/login'); /** * @api {post} /auth/register Register @@ -29,7 +29,7 @@ auth.post('/register', RegisterValidation, register); * @apiParam {String} email email of the user. * @apiParam {String} password password of the user. * - * @apiSuccess {string} access_token Access token. + * @apiSuccess {String} access_token Access token. */ auth.post('/login', LoginValidation, login); diff --git a/app/routes/auth/login.js b/app/routes/auth/login.js index 76f303f..f250ce8 100644 --- a/app/routes/auth/login.js +++ b/app/routes/auth/login.js @@ -31,7 +31,7 @@ module.exports = (req, res, next) => { const token = jwt.sign({ user: dataUser, }, secret, { - expiresIn: '12h', + expiresIn: '3h', }); // return the information including token as JSON diff --git a/app/routes/auth/register.js b/app/routes/auth/register.js index 567116e..bdfc616 100644 --- a/app/routes/auth/register.js +++ b/app/routes/auth/register.js @@ -13,8 +13,8 @@ module.exports = (req, res, next) => { password: passwordHash, }); - UserModel.countDocuments({ email: req.body.email }, (err, c) => { - if (c !== 0) { + UserModel.countDocuments({ email: req.body.email }, (err, count) => { + if (count !== 0) { return next({ status: 401, message: 'Email is already taken by another user.', From 576ad7cfbaf65c675855ae5123758f0f0b91c3d7 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:20:25 +0100 Subject: [PATCH 10/18] Note routes --- app/routes/note/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/routes/note/index.js b/app/routes/note/index.js index 3de1348..0c95137 100644 --- a/app/routes/note/index.js +++ b/app/routes/note/index.js @@ -7,7 +7,7 @@ const remove = require('./delete'); const CreateValidation = require.main.require('./app/validation/note/create'); const UpdateValidation = require.main.require('./app/validation/note/update'); -const Authentication = require.main.require('./app/validation/auth'); +const Authentication = require.main.require('./app/validation/auth/auth'); /** * @api {get} /note/:id Get note @@ -16,8 +16,8 @@ const Authentication = require.main.require('./app/validation/auth'); * * @apiParam {String} id Note unique ID. * - * @apiSuccess {string} title Title of the note. - * @apiSuccess {string} text Text of the note. + * @apiSuccess {String} title Title of the note. + * @apiSuccess {String} text Text of the note. */ note.get('/:id', Authentication, single); @@ -30,8 +30,8 @@ note.get('/:id', Authentication, single); * "Authorization": "" * } * - * @apiSuccess {string} title Title of the note. - * @apiSuccess {string} text Text of the note. + * @apiSuccess {String} title Title of the note. + * @apiSuccess {String} text Text of the note. */ note.post('/', Authentication, CreateValidation, create); @@ -42,8 +42,8 @@ note.post('/', Authentication, CreateValidation, create); * * @apiParam {String} id Note unique ID. * - * @apiSuccess {string} title Title of the note. - * @apiSuccess {string} text Text of the note. + * @apiSuccess {String} title Title of the note. + * @apiSuccess {String} text Text of the note. */ note.put('/:id', Authentication, UpdateValidation, update); From d88beab54062924d16af5f562442097602eff0d3 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Fri, 16 Nov 2018 18:20:25 +0100 Subject: [PATCH 11/18] User routes --- app/routes/user/index.js | 26 ++++++++++++++-------- app/routes/user/update.js | 45 ++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/app/routes/user/index.js b/app/routes/user/index.js index a245680..e496cdd 100644 --- a/app/routes/user/index.js +++ b/app/routes/user/index.js @@ -5,13 +5,16 @@ const update = require('./update'); const remove = require('./delete'); const notes = require('./notes'); -const Authentication = require.main.require('./app/validation/auth'); +const Authentication = require.main.require('./app/validation/auth/auth'); +const UpdateValidation = require.main.require('./app/validation/user/update'); +const DeleteValidation = require.main.require('./app/validation/user/delete'); /** * @api {get} /user/me Get account information * @apiName GetUser * @apiGroup User * + * @apiSuccess {String} id Unique ID of the User. * @apiSuccess {String} firstname Firstname of the User. * @apiSuccess {String} lastname Lastname of the User. * @apiSuccess {String} email Email of the User. @@ -24,22 +27,27 @@ user.get('/me', Authentication, profile); * @apiGroup User * @apiDescription Send only password and new_password to change the password. Otherwise they will be ignored. * - * @apiParam {String} Firstname New firstname. - * @apiParam {String} Lastname New lastname. - * @apiParam {String} Email New email address. - * @apiParam {String} Password Actual password. - * @apiParam {String} Password New password. + * @apiParam {String} firstname New firstname. (optional) + * @apiParam {String} lastname New lastname. (optional) + * @apiParam {String} email New email address. (optional) + * @apiParam {String} password Actual password. (optional) + * @apiParam {String} new_password New password (only if you passed password parameter). * - * @apiSuccess {Object} user User object. + * @apiSuccess {String} id Unique ID of the User. + * @apiSuccess {String} firstname Firstname of the User. + * @apiSuccess {String} lastname Lastname of the User. + * @apiSuccess {String} email Email of the User. */ -user.put('/me', Authentication, update); +user.put('/me', Authentication, UpdateValidation, update); /** * @api {delete} /user/me Delete account * @apiName DeleteUser * @apiGroup User + * + * @apiParam {String} password Account password. */ -user.delete('/me', Authentication, remove); +user.delete('/me', Authentication, DeleteValidation, remove); /** * @api {get} /user/me/notes Get all notes diff --git a/app/routes/user/update.js b/app/routes/user/update.js index 66c0e4b..3ebfab2 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -1,20 +1,45 @@ const mongoose = require('mongoose'); const jwt = require('jsonwebtoken'); +const bcrypt = require('bcrypt-nodejs'); module.exports = (req, res, next) => { const UserModel = mongoose.model('User'); const { user } = jwt.decode(req.headers.authorization); - return UserModel.findById(user.id, 'id firstname lastname email') - .lean() - .exec() - .then((result) => { - if (result === null) { - return next({ status: 401, message: 'User does not exists.' }); - } + return UserModel.findOne({ _id: user.id }, (err, userObj) => { + if (!userObj) { + return next({ status: 401, message: 'User does not exists.' }); + } - return res.status(200).json(result); - }) - .catch(() => next({ status: 401, message: 'User does not exists.' })); + if (req.body.password) { + bcrypt.compare(req.body.password, user.password, (error, result) => { + if (!result || error) { + return next( + { + status: 401, + message: 'Authentication failed. Wrong password.', + } + ); + } + + if (req.body.password === req.body.new_password) { + return next( + { + status: 401, + message: 'New password must be different than old password.', + } + ); + } + + userObj.password = bcrypt.hashSync(req.body.new_password); + }); + } else { + userObj.firstname = req.body.firstname || userObj.firstname; + userObj.lastname = req.body.lastname || userObj.lastname; + userObj.email = req.body.email || userObj.email; + } + + return userObj.save(() => res.status(200).json(userObj)); + }); }; From 9b5023d6591fa8f331382add21f8b65833180783 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 00:43:22 +0100 Subject: [PATCH 12/18] ESlint cfg --- .eslintrc.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index d3d9bfc..c15f0a9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,9 @@ { "extends": "airbnb-base", "rules": { - "max-len": ["error", { "comments": 120 }] + "max-len": ["error", { "code": 90, "comments": 120 }], + "no-param-reassign": ["error", { "props": false }], + "no-underscore-dangle": ["error", { "allow": ["_id"] }], + "no-unused-vars": ["error", {"args":"none"}] } } From 46d54d339fa712fcd687aa670d8ea22ce02c0c6a Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 00:43:34 +0100 Subject: [PATCH 13/18] User profile --- app/routes/user/profile.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/routes/user/profile.js b/app/routes/user/profile.js index 66c0e4b..357e1d6 100644 --- a/app/routes/user/profile.js +++ b/app/routes/user/profile.js @@ -9,12 +9,6 @@ module.exports = (req, res, next) => { return UserModel.findById(user.id, 'id firstname lastname email') .lean() .exec() - .then((result) => { - if (result === null) { - return next({ status: 401, message: 'User does not exists.' }); - } - - return res.status(200).json(result); - }) + .then(result => res.status(200).json(result)) .catch(() => next({ status: 401, message: 'User does not exists.' })); }; From b3b1a79bee1d9c65acc8f8eca76c468f542037fd Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 00:43:58 +0100 Subject: [PATCH 14/18] User update --- app/routes/user/update.js | 17 ++++++----------- app/validation/user/update.js | 9 +++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/routes/user/update.js b/app/routes/user/update.js index 3ebfab2..c9de5de 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -12,27 +12,22 @@ module.exports = (req, res, next) => { return next({ status: 401, message: 'User does not exists.' }); } - if (req.body.password) { + if (req.body.password && req.body.new_password) { bcrypt.compare(req.body.password, user.password, (error, result) => { if (!result || error) { return next( { status: 401, message: 'Authentication failed. Wrong password.', - } + }, ); } - if (req.body.password === req.body.new_password) { - return next( - { - status: 401, - message: 'New password must be different than old password.', - } - ); - } + return bcrypt.hash(req.body.new_password, null, null, (hashErr, hash) => { + userObj.password = hash; - userObj.password = bcrypt.hashSync(req.body.new_password); + return userObj.save(() => res.status(200).json(userObj)); + }); }); } else { userObj.firstname = req.body.firstname || userObj.firstname; diff --git a/app/validation/user/update.js b/app/validation/user/update.js index 7b1c56c..64b6feb 100644 --- a/app/validation/user/update.js +++ b/app/validation/user/update.js @@ -28,6 +28,15 @@ module.exports = (req, res, next) => { }); } + /*if (req.body.password && req.body.password === req.body.new_password) { + return next( + { + status: 401, + message: 'New password must be different than old password.', + }, + ); + }*/ + return next(); }); }; From 119209a73fd282bb313f108881e7d0087179fc46 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 00:53:21 +0100 Subject: [PATCH 15/18] [Fix #6] Account update --- app/routes/user/update.js | 6 +++--- app/validation/user/update.js | 9 --------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/app/routes/user/update.js b/app/routes/user/update.js index c9de5de..4b0e19f 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -13,7 +13,7 @@ module.exports = (req, res, next) => { } if (req.body.password && req.body.new_password) { - bcrypt.compare(req.body.password, user.password, (error, result) => { + bcrypt.compare(req.body.password, userObj.password, (error, result) => { if (!result || error) { return next( { @@ -33,8 +33,8 @@ module.exports = (req, res, next) => { userObj.firstname = req.body.firstname || userObj.firstname; userObj.lastname = req.body.lastname || userObj.lastname; userObj.email = req.body.email || userObj.email; - } - return userObj.save(() => res.status(200).json(userObj)); + return userObj.save(() => res.status(200).json(userObj)); + } }); }; diff --git a/app/validation/user/update.js b/app/validation/user/update.js index 64b6feb..7b1c56c 100644 --- a/app/validation/user/update.js +++ b/app/validation/user/update.js @@ -28,15 +28,6 @@ module.exports = (req, res, next) => { }); } - /*if (req.body.password && req.body.password === req.body.new_password) { - return next( - { - status: 401, - message: 'New password must be different than old password.', - }, - ); - }*/ - return next(); }); }; From 407f3d3ba73f1d29fc12125156a0305c12156d15 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 00:58:21 +0100 Subject: [PATCH 16/18] [Fix #4] Change account password --- app/routes/user/update.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/routes/user/update.js b/app/routes/user/update.js index 4b0e19f..fa6cc24 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -26,7 +26,15 @@ module.exports = (req, res, next) => { return bcrypt.hash(req.body.new_password, null, null, (hashErr, hash) => { userObj.password = hash; - return userObj.save(() => res.status(200).json(userObj)); + const response = { + _id: userObj._id, + firstname: userObj.firstname, + lastname: userObj.lastname, + email: userObj.email, + createdAt: userObj.createdAt, + }; + + return userObj.save(() => res.status(200).json(response)); }); }); } else { @@ -34,7 +42,15 @@ module.exports = (req, res, next) => { userObj.lastname = req.body.lastname || userObj.lastname; userObj.email = req.body.email || userObj.email; - return userObj.save(() => res.status(200).json(userObj)); + const response = { + _id: userObj._id, + firstname: userObj.firstname, + lastname: userObj.lastname, + email: userObj.email, + createdAt: userObj.createdAt, + }; + + return userObj.save(() => res.status(200).json(response)); } }); }; From 319d1b9dbdb804b0c918c3b933c9e743b734a34b Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 01:01:35 +0100 Subject: [PATCH 17/18] API docs --- docs/api_data.js | 36 ++++++++++++++++++++++++++++++++---- docs/api_data.json | 36 ++++++++++++++++++++++++++++++++---- docs/api_project.js | 2 +- docs/api_project.json | 2 +- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/docs/api_data.js b/docs/api_data.js index caf1f12..1d1fac8 100644 --- a/docs/api_data.js +++ b/docs/api_data.js @@ -308,7 +308,7 @@ define({ "api": [ "group": "Parameter", "type": "String", "optional": false, - "field": "Password", + "field": "password", "description": "

Account password.

" } ] @@ -327,6 +327,13 @@ define({ "api": [ "success": { "fields": { "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "id", + "description": "

Unique ID of the User.

" + }, { "group": "Success 200", "type": "String", @@ -408,10 +415,31 @@ define({ "api": [ "Success 200": [ { "group": "Success 200", - "type": "Object", + "type": "String", "optional": false, - "field": "user", - "description": "

User object.

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

Unique ID of the User.

" + }, + { + "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": "email", + "description": "

Email of the User.

" } ] } diff --git a/docs/api_data.json b/docs/api_data.json index 2ead4d6..e9c24cc 100644 --- a/docs/api_data.json +++ b/docs/api_data.json @@ -308,7 +308,7 @@ "group": "Parameter", "type": "String", "optional": false, - "field": "Password", + "field": "password", "description": "

Account password.

" } ] @@ -327,6 +327,13 @@ "success": { "fields": { "Success 200": [ + { + "group": "Success 200", + "type": "String", + "optional": false, + "field": "id", + "description": "

Unique ID of the User.

" + }, { "group": "Success 200", "type": "String", @@ -408,10 +415,31 @@ "Success 200": [ { "group": "Success 200", - "type": "Object", + "type": "String", "optional": false, - "field": "user", - "description": "

User object.

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

Unique ID of the User.

" + }, + { + "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": "email", + "description": "

Email of the User.

" } ] } diff --git a/docs/api_project.js b/docs/api_project.js index 63d3c23..07c24d7 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-16T14:21:42.357Z", + "time": "2018-11-17T00:00:47.768Z", "url": "http://apidocjs.com", "version": "0.17.7" } diff --git a/docs/api_project.json b/docs/api_project.json index c4a6d38..8f24bc2 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-16T14:21:42.357Z", + "time": "2018-11-17T00:00:47.768Z", "url": "http://apidocjs.com", "version": "0.17.7" } From b9a7b01c1b94caf8305511ea8f0838a2365bda51 Mon Sep 17 00:00:00 2001 From: sundowndev Date: Sat, 17 Nov 2018 01:01:52 +0100 Subject: [PATCH 18/18] Account update bugfix --- app/routes/user/update.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/routes/user/update.js b/app/routes/user/update.js index fa6cc24..e53eae2 100644 --- a/app/routes/user/update.js +++ b/app/routes/user/update.js @@ -13,7 +13,7 @@ module.exports = (req, res, next) => { } if (req.body.password && req.body.new_password) { - bcrypt.compare(req.body.password, userObj.password, (error, result) => { + return bcrypt.compare(req.body.password, userObj.password, (error, result) => { if (!result || error) { return next( { @@ -37,20 +37,20 @@ module.exports = (req, res, next) => { return userObj.save(() => res.status(200).json(response)); }); }); - } else { - userObj.firstname = req.body.firstname || userObj.firstname; - userObj.lastname = req.body.lastname || userObj.lastname; - userObj.email = req.body.email || userObj.email; - - const response = { - _id: userObj._id, - firstname: userObj.firstname, - lastname: userObj.lastname, - email: userObj.email, - createdAt: userObj.createdAt, - }; - - return userObj.save(() => res.status(200).json(response)); } + + userObj.firstname = req.body.firstname || userObj.firstname; + userObj.lastname = req.body.lastname || userObj.lastname; + userObj.email = req.body.email || userObj.email; + + const response = { + _id: userObj._id, + firstname: userObj.firstname, + lastname: userObj.lastname, + email: userObj.email, + createdAt: userObj.createdAt, + }; + + return userObj.save(() => res.status(200).json(response)); }); };