From 6ae915444d21a25c329d78ef9636e760f278f091 Mon Sep 17 00:00:00 2001 From: angelalvaigle Date: Thu, 12 Dec 2024 00:57:57 +0100 Subject: [PATCH] user add & update validations --- docker-compose.yml | 2 + middleware/validation-middleware.js | 90 +++++++++++++++++++++++++++++ users/authservice/package-lock.json | 29 ++++++++++ users/authservice/package.json | 3 +- users/userservice/package-lock.json | 29 ++++++++++ users/userservice/package.json | 3 +- users/userservice/user-router.js | 13 ++++- webapp/src/pages/Profile.jsx | 2 +- 8 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 middleware/validation-middleware.js diff --git a/docker-compose.yml b/docker-compose.yml index 427b7f8..e575220 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,8 @@ services: profiles: ['dev', 'prod'] build: ./users/authservice volumes: + - ./errors:/usr/src/authservice/errors + - ./middleware:/usr/src/authservice/middleware - ./utils:/usr/src/authservice/utils depends_on: - mongodb diff --git a/middleware/validation-middleware.js b/middleware/validation-middleware.js new file mode 100644 index 0000000..31736f4 --- /dev/null +++ b/middleware/validation-middleware.js @@ -0,0 +1,90 @@ +import { body, param, validationResult } from 'express-validator'; +import { BadRequestError } from '../errors/customErrors.js'; +import User from '../user-model.js'; + +const withValidationErrors = (validateValues) => { + return [ + validateValues, + (req, res, next) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + const errorMessages = errors.array().map((error) => error.msg); + throw new BadRequestError(errorMessages); + } + next(); + }, + ]; +}; + +export const validateRegisterInput = withValidationErrors([ + body('name') + .notEmpty() + .withMessage('name is required') + .isLength({ max: 20 }) + .withMessage('name must be no more than 20 characters long'), + body('lastName') + .notEmpty() + .withMessage('last name is required') + .isLength({ max: 20 }) + .withMessage('last name must be no more than 20 characters long'), + body('username') + .notEmpty() + .withMessage('username is required') + .isLength({ max: 20 }) + .withMessage('username must be no more than 20 characters long'), + body('email') + .notEmpty() + .withMessage('email is required') + .isLength({ max: 40 }) + .withMessage('email must be no more than 20 characters long') + .isEmail() + .withMessage('invalid email format') + .isLength({ max: 40 }) + .withMessage('email must be no more than 20 characters long') + .custom(async (email) => { + const user = await User.findOne({ email }); + if (user) throw new BadRequestError('email already exists'); + }), + body('password') + .notEmpty() + .withMessage('password is required') + .isLength({ min: 8 }) + .withMessage('password must be at least 8 characters long') + .isLength({ max: 20 }) + .withMessage('password must be no more than 20 characters long'), +]); + +export const validateUpdateUserInput = withValidationErrors([ + body('name') + .notEmpty() + .withMessage('name is required') + .isLength({ max: 20 }) + .withMessage('name must be no more than 20 characters long'), + body('lastName') + .notEmpty() + .withMessage('last name is required') + .isLength({ max: 40 }) + .withMessage('last name must be no more than 20 characters long'), + body('username') + .notEmpty() + .withMessage('username is required') + .isLength({ max: 20 }) + .withMessage('username must be no more than 20 characters long'), + body('email') + .notEmpty() + .withMessage('email is required') + .isLength({ max: 40 }) + .withMessage('email must be no more than 20 characters long') + .isEmail() + .withMessage('invalid email format') + .isLength({ max: 40 }) + .withMessage('email must be no more than 20 characters long') + .custom(async (email, { req }) => { + const user = await User.findOne({ email }); + console.log(user); + console.log(req.user); + if (user && user._id.toString() !== req.user.userId) { + throw new BadRequestError('email already exists'); + } + }), +]); diff --git a/users/authservice/package-lock.json b/users/authservice/package-lock.json index a4adb47..4199f5c 100644 --- a/users/authservice/package-lock.json +++ b/users/authservice/package-lock.json @@ -12,6 +12,7 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.2", "express": "^4.18.2", + "express-validator": "^7.0.1", "http-status-codes": "^2.2.0", "jsonwebtoken": "^9.0.2", "mongodb-memory-server": "^10.1.2", @@ -3478,6 +3479,19 @@ "node": ">= 0.10.0" } }, + "node_modules/express-validator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.2.0.tgz", + "integrity": "sha512-I2ByKD8panjtr8Y05l21Wph9xk7kk64UMyvJCl/fFM/3CTJq8isXYPLeKW/aZBCdb/LYNv63PwhY8khw8VWocA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "validator": "~13.12.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/express/node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -4897,6 +4911,12 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -6720,6 +6740,15 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/users/authservice/package.json b/users/authservice/package.json index 37928e9..c12c1a8 100644 --- a/users/authservice/package.json +++ b/users/authservice/package.json @@ -28,7 +28,8 @@ "http-status-codes": "^2.2.0", "jsonwebtoken": "^9.0.2", "mongoose": "^8.0.4", - "mongodb-memory-server": "^10.1.2" + "mongodb-memory-server": "^10.1.2", + "express-validator": "^7.0.1" }, "devDependencies": { "@babel/preset-env": "^7.26.0", diff --git a/users/userservice/package-lock.json b/users/userservice/package-lock.json index cf4e7d9..71650ba 100644 --- a/users/userservice/package-lock.json +++ b/users/userservice/package-lock.json @@ -12,6 +12,7 @@ "bcrypt": "^5.1.1", "body-parser": "^1.20.2", "express": "^4.18.2", + "express-validator": "^7.0.1", "http-status-codes": "^2.3.0", "jsonwebtoken": "^9.0.2", "mongoose": "^8.0.4" @@ -2263,6 +2264,19 @@ "node": ">= 0.10.0" } }, + "node_modules/express-validator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.2.0.tgz", + "integrity": "sha512-I2ByKD8panjtr8Y05l21Wph9xk7kk64UMyvJCl/fFM/3CTJq8isXYPLeKW/aZBCdb/LYNv63PwhY8khw8VWocA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "validator": "~13.12.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/express/node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -3717,6 +3731,12 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -5400,6 +5420,15 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/users/userservice/package.json b/users/userservice/package.json index 78837ce..fa75e95 100644 --- a/users/userservice/package.json +++ b/users/userservice/package.json @@ -27,7 +27,8 @@ "express": "^4.18.2", "http-status-codes": "^2.3.0", "jsonwebtoken": "^9.0.2", - "mongoose": "^8.0.4" + "mongoose": "^8.0.4", + "express-validator": "^7.0.1" }, "devDependencies": { "jest": "^29.7.0", diff --git a/users/userservice/user-router.js b/users/userservice/user-router.js index f4a595c..3e479b0 100644 --- a/users/userservice/user-router.js +++ b/users/userservice/user-router.js @@ -7,13 +7,22 @@ import { updateUserController, } from './user-controller.js'; import { authenticateUser } from './middleware/auth-middleware.js'; +import { + validateRegisterInput, + validateUpdateUserInput, +} from './middleware/validation-middleware.js'; const userRouter = express.Router(); // Define la ruta para el login y asocia el controlador -userRouter.post('/adduser', addUserController); +userRouter.post('/adduser', validateRegisterInput, addUserController); userRouter.get('/users', getUsersController); userRouter.get('/current-user', authenticateUser, getCurrentUserController); -userRouter.patch('/update-user', authenticateUser, updateUserController); +userRouter.patch( + '/update-user', + authenticateUser, + validateUpdateUserInput, + updateUserController +); export default userRouter; diff --git a/webapp/src/pages/Profile.jsx b/webapp/src/pages/Profile.jsx index 44662fa..31ba009 100644 --- a/webapp/src/pages/Profile.jsx +++ b/webapp/src/pages/Profile.jsx @@ -42,7 +42,7 @@ const Profile = () => { ); setOpenSnackbar(true); } catch (error) { - setError(error?.response?.data?.msg); + setError(error || 'An error occurred'); } return null; };