feat(validation): introduce express-validator on CMS user and article endpoints
Replaces the broken fieldValidation helper (called next() without return, so execution continued on invalid input) with express-validator chains applied at the route level. Validation covers: email format, username constraints, password min length, field lengths, URL and phone formats. products and tags controllers retain their local fieldValidation pending a separate ecommerce validation pass.
This commit is contained in:
@@ -8,10 +8,6 @@ module.exports.createArticle = asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
const loggedUser = await UserService.getLoggedUserById(req.payload.id);
|
||||
|
||||
fieldValidation(req.body.article.title, next);
|
||||
fieldValidation(req.body.article.description, next);
|
||||
fieldValidation(req.body.article.body, next);
|
||||
|
||||
const { title, description, body, tagList } = req.body.article;
|
||||
const articleSlug = ArticleService.slugify(title);
|
||||
const slugInDB = await ArticleService.isSlugUsed(articleSlug);
|
||||
@@ -254,8 +250,3 @@ module.exports.deleteFavoriteArticle = asyncHandler(async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
const fieldValidation = (field, next) => {
|
||||
if (!field) {
|
||||
return next(new ErrorResponse(`Missing fields`, 400));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,10 +32,6 @@ module.exports.authenticate = asyncHandler(async (req, res, next) => {
|
||||
|
||||
module.exports.createUser = asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
fieldValidation(req.body.user.username, next);
|
||||
fieldValidation(req.body.user.email, next);
|
||||
fieldValidation(req.body.user.password, next);
|
||||
|
||||
const { username, firstname, lastname, phone, email, password } = req.body.user;
|
||||
const userSlug = UserService.slugify(username);
|
||||
const slugInDB = await UserService.isUsernameUsed(userSlug);
|
||||
@@ -92,12 +88,6 @@ module.exports.getUser = asyncHandler(async (req, res, next) => {
|
||||
|
||||
module.exports.loginAsUser = asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
if (!req.body.user.email) {
|
||||
return res.status(422).json({ errors: { email: "email can't be blank" } });
|
||||
}
|
||||
if (!req.body.user.password) {
|
||||
return res.status(422).json({ errors: { password: " password can't be blank" } });
|
||||
}
|
||||
passport.authenticate('local', { session: false }, function (err, user, info) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
@@ -161,7 +151,6 @@ module.exports.updateUserEmail = asyncHandler(async (req, res, next) => {
|
||||
return next(new ErrorResponse("Unauthorized", 401, "You are not allowed to access this resource."));
|
||||
}
|
||||
|
||||
fieldValidation(req.body.user.email, next);
|
||||
if (typeof req.body.user.email !== 'undefined') {
|
||||
user.email = req.body.user.email;
|
||||
}
|
||||
@@ -205,7 +194,6 @@ module.exports.updateUserRole = asyncHandler(async (req, res, next) => {
|
||||
return next(new ErrorResponse("Forbidden", 403, "You are not allowed to change user roles."));
|
||||
}
|
||||
|
||||
fieldValidation(req.body.user.role, next);
|
||||
if (typeof req.body.user.role !== 'undefined') {
|
||||
user.role = req.body.user.role;
|
||||
}
|
||||
@@ -226,7 +214,6 @@ module.exports.updateUserUsername = asyncHandler(async (req, res, next) => {
|
||||
return next(new ErrorResponse("Unauthorized", 401, "You are not allowed to access this resource."));
|
||||
}
|
||||
|
||||
fieldValidation(req.body.user.username, next);
|
||||
if (typeof req.body.user.username !== 'undefined') {
|
||||
user.username = req.body.user.username;
|
||||
}
|
||||
@@ -240,8 +227,3 @@ module.exports.updateUserUsername = asyncHandler(async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
const fieldValidation = (field, next) => {
|
||||
if (!field) {
|
||||
return next(new ErrorResponse(`Missing fields`, 400));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
const { validationResult } = require('express-validator');
|
||||
|
||||
const validate = (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(422).json({ errors: errors.mapped() });
|
||||
}
|
||||
return next();
|
||||
};
|
||||
|
||||
module.exports = validate;
|
||||
@@ -0,0 +1,27 @@
|
||||
const { body } = require('express-validator');
|
||||
|
||||
const createArticleRules = [
|
||||
body('article.title')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isLength({ max: 255 }).withMessage('must be at most 255 characters')
|
||||
.trim(),
|
||||
body('article.description')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isLength({ max: 1000 }).withMessage('must be at most 1000 characters')
|
||||
.trim(),
|
||||
body('article.body')
|
||||
.notEmpty().withMessage("can't be blank"),
|
||||
];
|
||||
|
||||
const updateArticleRules = [
|
||||
body('article.title')
|
||||
.optional()
|
||||
.isLength({ max: 255 }).withMessage('must be at most 255 characters')
|
||||
.trim(),
|
||||
body('article.description')
|
||||
.optional()
|
||||
.isLength({ max: 1000 }).withMessage('must be at most 1000 characters')
|
||||
.trim(),
|
||||
];
|
||||
|
||||
module.exports = { createArticleRules, updateArticleRules };
|
||||
@@ -0,0 +1,63 @@
|
||||
const { body } = require('express-validator');
|
||||
|
||||
const createUserRules = [
|
||||
body('user.email')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isEmail().withMessage('must be a valid email address')
|
||||
.normalizeEmail(),
|
||||
body('user.username')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isLength({ min: 3, max: 50 }).withMessage('must be between 3 and 50 characters')
|
||||
.matches(/^[a-zA-Z0-9_.-]+$/).withMessage('must contain only letters, numbers, underscores, dots or hyphens'),
|
||||
body('user.password')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isLength({ min: 8 }).withMessage('must be at least 8 characters'),
|
||||
];
|
||||
|
||||
const loginRules = [
|
||||
body('user.email')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isEmail().withMessage('must be a valid email address')
|
||||
.normalizeEmail(),
|
||||
body('user.password')
|
||||
.notEmpty().withMessage("can't be blank"),
|
||||
];
|
||||
|
||||
const updateUserRules = [
|
||||
body('user.firstname')
|
||||
.optional()
|
||||
.isLength({ max: 100 }).withMessage('must be at most 100 characters')
|
||||
.trim(),
|
||||
body('user.lastname')
|
||||
.optional()
|
||||
.isLength({ max: 100 }).withMessage('must be at most 100 characters')
|
||||
.trim(),
|
||||
body('user.phone')
|
||||
.optional()
|
||||
.isMobilePhone().withMessage('must be a valid phone number'),
|
||||
body('user.image')
|
||||
.optional()
|
||||
.isURL().withMessage('must be a valid URL'),
|
||||
];
|
||||
|
||||
const updateEmailRules = [
|
||||
body('user.email')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isEmail().withMessage('must be a valid email address')
|
||||
.normalizeEmail(),
|
||||
];
|
||||
|
||||
const updateUsernameRules = [
|
||||
body('user.username')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isLength({ min: 3, max: 50 }).withMessage('must be between 3 and 50 characters')
|
||||
.matches(/^[a-zA-Z0-9_.-]+$/).withMessage('must contain only letters, numbers, underscores, dots or hyphens'),
|
||||
];
|
||||
|
||||
const updateRoleRules = [
|
||||
body('user.role')
|
||||
.notEmpty().withMessage("can't be blank")
|
||||
.isIn(['Admin', 'User']).withMessage('must be Admin or User'),
|
||||
];
|
||||
|
||||
module.exports = { createUserRules, loginRules, updateUserRules, updateEmailRules, updateUsernameRules, updateRoleRules };
|
||||
@@ -10,14 +10,16 @@ const {
|
||||
deleteFavoriteArticle
|
||||
} = require('../../../controllers/articles.controller');
|
||||
const auth = require('../../../middlewares/auth');
|
||||
const validate = require('../../../middlewares/validate');
|
||||
const { createArticleRules, updateArticleRules } = require('../../../middlewares/validators/articles.validators');
|
||||
|
||||
const articleRouter = express.Router();
|
||||
|
||||
articleRouter.get('/', auth.optional, getArticles);
|
||||
articleRouter.post('/', auth.required, createArticle);
|
||||
articleRouter.post('/', auth.required, createArticleRules, validate, createArticle);
|
||||
articleRouter.get('/feed', auth.required, articlesFeed);
|
||||
articleRouter.get('/:slug', auth.optional, getArticle);
|
||||
articleRouter.put('/:slug', auth.required, updateArticle);
|
||||
articleRouter.put('/:slug', auth.required, updateArticleRules, validate, updateArticle);
|
||||
articleRouter.delete('/:slug', auth.required, deleteArticle);
|
||||
articleRouter.post('/:slug/favorite', auth.required, addFavoriteArticle);
|
||||
articleRouter.delete('/:slug/favorite', auth.required, deleteFavoriteArticle);
|
||||
|
||||
@@ -5,6 +5,8 @@ const {
|
||||
updateUser, updateUserEmail, updateUserPassword, updateUserRole, updateUserUsername
|
||||
} = require('../../../controllers/users.controller');
|
||||
const auth = require('../../../middlewares/auth');
|
||||
const validate = require('../../../middlewares/validate');
|
||||
const { createUserRules, loginRules, updateUserRules, updateEmailRules, updateUsernameRules, updateRoleRules } = require('../../../middlewares/validators/users.validators');
|
||||
|
||||
const userRouter = express.Router();
|
||||
|
||||
@@ -17,15 +19,15 @@ const authLimiter = rateLimit({
|
||||
});
|
||||
|
||||
userRouter.get('/', auth.required, getUser);
|
||||
userRouter.put('/', auth.required, updateUser);
|
||||
userRouter.post('/', authLimiter, auth.optional, createUser);
|
||||
userRouter.put('/', auth.required, updateUserRules, validate, updateUser);
|
||||
userRouter.post('/', authLimiter, auth.optional, createUserRules, validate, createUser);
|
||||
userRouter.get('/authenticate', auth.optional, authenticate);
|
||||
userRouter.post('/login', authLimiter, auth.optional, loginAsUser);
|
||||
userRouter.post('/login', authLimiter, auth.optional, loginRules, validate, loginAsUser);
|
||||
//userRouter.post('/register', auth.optional, createUser);
|
||||
//userRouter.get('/users', auth.required, getAllUsers);
|
||||
userRouter.put('/update/email', auth.required, updateUserEmail);
|
||||
userRouter.put('/update/email', auth.required, updateEmailRules, validate, updateUserEmail);
|
||||
userRouter.put('/update/password', auth.required, updateUserPassword);
|
||||
userRouter.put('/update/role', auth.required, updateUserRole);
|
||||
userRouter.put('/update/username', auth.required, updateUserUsername);
|
||||
userRouter.put('/update/role', auth.required, updateRoleRules, validate, updateUserRole);
|
||||
userRouter.put('/update/username', auth.required, updateUsernameRules, validate, updateUserUsername);
|
||||
|
||||
module.exports = userRouter;
|
||||
|
||||
Reference in New Issue
Block a user