From 5bf9a2ade660441d260c0be971dba35b72b5453d Mon Sep 17 00:00:00 2001 From: Divlo Date: Tue, 7 Apr 2020 16:21:48 +0200 Subject: [PATCH] backend: PUT /users - Modifier le profil --- api/controllers/admin.js | 5 +- api/controllers/categories.js | 2 +- api/controllers/functions.js | 7 +- api/controllers/users.js | 68 +++++++++++++++++--- api/routes/admin.js | 118 +++++++++++++++++----------------- api/routes/users.js | 55 ++++++++++++++++ 6 files changed, 180 insertions(+), 75 deletions(-) diff --git a/api/controllers/admin.js b/api/controllers/admin.js index 276510e..38eeb7e 100644 --- a/api/controllers/admin.js +++ b/api/controllers/admin.js @@ -10,7 +10,6 @@ exports.postFunction = (req, res, next) => { const image = req.files.image; const errors = validationResult(req); if (!errors.isEmpty()) { - console.log(errors.array()) return errorHandling(next, { message: errors.array()[0].msg, statusCode: 400 }); } if (!image || image.truncated && ( @@ -28,7 +27,7 @@ exports.postFunction = (req, res, next) => { return res.status(201).json({ message: "La fonction a été correctement ajouté!"}); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } }); } @@ -48,6 +47,6 @@ exports.deleteFunction = async (req, res, next) => { res.status(200).json({ message: "La fonction a été correctement supprimé!"}); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } \ No newline at end of file diff --git a/api/controllers/categories.js b/api/controllers/categories.js index 9da3bf4..dec7714 100644 --- a/api/controllers/categories.js +++ b/api/controllers/categories.js @@ -8,6 +8,6 @@ exports.getCategories = (_req, res, next) => { }) .catch((error) => { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); }); } \ No newline at end of file diff --git a/api/controllers/functions.js b/api/controllers/functions.js index 7299019..536d3b8 100644 --- a/api/controllers/functions.js +++ b/api/controllers/functions.js @@ -37,7 +37,8 @@ exports.getFunctions = (req, res, next) => { ], attributes: { exclude: ["updatedAt", "utilizationForm", "article", "isOnline"] - } + }, + order: [['createdAt', 'DESC']] }) .then((result) => { const { count, rows } = result; @@ -46,7 +47,7 @@ exports.getFunctions = (req, res, next) => { }) .catch((error) => { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); }); } @@ -69,7 +70,7 @@ exports.getFunctionBySlug = (req, res, next) => { }) .catch((error) => { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); }); } diff --git a/api/controllers/users.js b/api/controllers/users.js index e6fc0dc..6ebe121 100644 --- a/api/controllers/users.js +++ b/api/controllers/users.js @@ -1,3 +1,4 @@ +const path = require('path'); const { validationResult } = require('express-validator'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); @@ -14,6 +15,55 @@ const Functions = require('../models/functions'); const Categories = require('../models/categories'); const Comments = require('../models/comments'); +async function handleEditUser(res, { name, email, biography, isPublicEmail }, userId, logoName) { + const user = await Users.findOne({ where: { id: userId } }); + user.name = name; + user.email = email; + user.biography = biography; + user.isPublicEmail = isPublicEmail; + if (logoName != undefined) { + user.logo = `/images/users/${logoName}`; + } + await user.save(); + return res.status(200).json({ message: "Le profil a bien été modifié!" }); +} + +exports.putUser = (req, res, next) => { + const { name, email, biography, isPublicEmail } = req.body; + const logo = req.files.logo; + const errors = validationResult(req); + if (!errors.isEmpty()) { + return errorHandling(next, { message: errors.array()[0].msg, statusCode: 400 }); + } + if (logo != undefined) { + if (!logo || logo.truncated && ( + logo.mimetype !== 'image/png' || + logo.mimetype !== 'image/jpg' || + logo.mimetype !== 'image/jpeg' || + logo.mimetype !== 'image/gif' + )) { + return errorHandling(next, { message:"Le profil doit avoir une image valide.", statusCode: 400 }); + } + const logoName = name + uuid.v4() + logo.name; + logo.mv(path.join(__dirname, '..', 'assets', 'images', 'users') + '/' + logoName, async (error) => { + if (error) return errorHandling(next, serverError); + try { + return handleEditUser(res, { name, email, biography, isPublicEmail }, req.userId, logoName); + } catch (error) { + console.log(error); + return errorHandling(next, serverError); + } + }); + } else { + try { + return handleEditUser(res, { name, email, biography, isPublicEmail }, req.userId, null); + } catch (error) { + console.log(error); + return errorHandling(next, serverError); + } + } +} + exports.register = async (req, res, next) => { const { name, email, password } = req.body; const errors = validationResult(req); @@ -33,7 +83,7 @@ exports.register = async (req, res, next) => { return res.status(201).json({ result: "Vous y êtes presque, veuillez vérifier vos emails pour confirmer l'inscription." }); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } @@ -57,11 +107,11 @@ exports.login = async (req, res, next) => { } const token = jwt.sign({ email: user.email, userId: user.id - }, JWT_SECRET, { expiresIn: '1h' }); + }, JWT_SECRET, { expiresIn: '3h' }); return res.status(200).json({ token, id: user.id, name: user.name, email: user.email, biography: user.biography, logo: user.logo, isPublicEmail: user.isPublicEmail, isAdmin: user.isAdmin, createdAt: user.createdAt }); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } @@ -81,7 +131,7 @@ exports.confirmEmail = async (req, res, next) => { return res.redirect(`${FRONT_END_HOST}/login?isConfirmed=true`); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } @@ -109,7 +159,7 @@ exports.resetPassword = async (req, res, next) => { return res.status(200).json({ result: "Demande de réinitialisation du mot de passe réussi, veuillez vérifier vos emails!" }); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } @@ -132,7 +182,7 @@ exports.newPassword = async (req, res, next) => { return res.status(200).json({ result: "Le mot de passe a bien été modifié!" }); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } @@ -156,10 +206,12 @@ exports.getUserInfo = async (req, res, next) => { }); const favoritesArray = favorites.map((favorite) => favorite.function); const comments = await Comments.findAll({ + limit: 10, where: { userId: user.id }, include: [ { model: Functions, attributes: { exclude: ["updatedAt", "utilizationForm", "article", "isOnline"] } } - ] + ], + order: [['createdAt', 'DESC']] }); const commentsArray = comments.map((commentObject) => { return { @@ -182,6 +234,6 @@ exports.getUserInfo = async (req, res, next) => { return res.status(200).json(userObject); } catch (error) { console.log(error); - errorHandling(next, serverError); + return errorHandling(next, serverError); } } \ No newline at end of file diff --git a/api/routes/admin.js b/api/routes/admin.js index 745f69b..823fcf5 100644 --- a/api/routes/admin.js +++ b/api/routes/admin.js @@ -11,68 +11,66 @@ const AdminRouter = Router(); // Permet de créé une fonction AdminRouter.post('/functions', isAuth, isAdmin, - fileUpload({ - useTempFiles: true, - safeFileNames: true, - preserveExtension: Number, - limits: { fileSize: 5 * 1024 * 1024 }, // 5mb, - parseNested: true - }), - [ - body('title') - .not() - .isEmpty() - .withMessage("La fonction doit avoir un titre.") - .isLength({ max: 100 }) - .withMessage("Le titre est trop long."), - body('slug') - .not() - .isEmpty() - .withMessage("La fonction doit avoir un slug.") - .isLength({ max: 100 }) - .withMessage("Le slug est trop long.") - .custom((async (slug) => { - try { - const FunctionSlug = await Functions.findOne({ where: { slug } }); - if (FunctionSlug) { - return Promise.reject("Le slug existe déjà..."); - } - } catch (error) { - console.log(error); +fileUpload({ + useTempFiles: true, + safeFileNames: true, + preserveExtension: Number, + limits: { fileSize: 5 * 1024 * 1024 }, // 5mb, + parseNested: true +}), +[ + body('title') + .not() + .isEmpty() + .withMessage("La fonction doit avoir un titre.") + .isLength({ max: 100 }) + .withMessage("Le titre est trop long."), + body('slug') + .not() + .isEmpty() + .withMessage("La fonction doit avoir un slug.") + .isLength({ max: 100 }) + .withMessage("Le slug est trop long.") + .custom((async (slug) => { + try { + const FunctionSlug = await Functions.findOne({ where: { slug } }); + if (FunctionSlug) { + return Promise.reject("Le slug existe déjà..."); } - return true; - })), - body('description') - .not() - .isEmpty() - .withMessage("La fonction doit avoir une description.") - .isLength({ max: 255 }) - .withMessage("La description est trop longue."), - body('categorieId') - .not() - .isEmpty() - .withMessage("La fonction doit avoir une catégorie.") - .custom(async (categorieId) => { - try { - const categorieFound = await Categories.findOne({ where: { id: categorieId } }); - if (!categorieFound) { - return Promise.reject("La catégorie n'existe pas!"); - } - } catch (error) { - console.log(error); + } catch (error) { + console.log(error); + } + return true; + })), + body('description') + .not() + .isEmpty() + .withMessage("La fonction doit avoir une description.") + .isLength({ max: 255 }) + .withMessage("La description est trop longue."), + body('categorieId') + .not() + .isEmpty() + .withMessage("La fonction doit avoir une catégorie.") + .custom(async (categorieId) => { + try { + const categorieFound = await Categories.findOne({ where: { id: categorieId } }); + if (!categorieFound) { + return Promise.reject("La catégorie n'existe pas!"); } - return true; - }), - body('type') - .custom((type) => { - if (!(type === 'article' || type === 'form' || type === 'page')) { - return Promise.reject('Le type de la fonction peut être : article, form ou page.'); - } - return true; - }) - ], - adminController.postFunction -); + } catch (error) { + console.log(error); + } + return true; + }), + body('type') + .custom((type) => { + if (!(type === 'article' || type === 'form' || type === 'page')) { + return Promise.reject('Le type de la fonction peut être : article, form ou page.'); + } + return true; + }) +], adminController.postFunction); // Supprime une fonction avec son id AdminRouter.delete('/functions/:id', isAuth, isAdmin, adminController.deleteFunction); diff --git a/api/routes/users.js b/api/routes/users.js index 0dfd6e8..584d0fa 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -1,8 +1,10 @@ const { Router } = require('express'); const { body } = require('express-validator'); +const fileUpload = require('express-fileupload'); const usersController = require('../controllers/users'); const { requiredFields } = require('../assets/config/errors'); const Users = require('../models/users'); +const isAuth = require('../middlewares/isAuth'); const UsersRouter = Router(); @@ -21,6 +23,59 @@ UsersRouter.post('/login', [ // Récupère les informations public d'un profil UsersRouter.get('/:name', usersController.getUserInfo); +// Permet de modifier son profil +UsersRouter.put('/', isAuth, +fileUpload({ + useTempFiles: true, + safeFileNames: true, + preserveExtension: Number, + limits: { fileSize: 5 * 1024 * 1024 }, // 5mb, + parseNested: true +}), +[ + body('email') + .isEmail() + .withMessage("Veuillez rentré une adresse mail valide.") + .custom((async (email) => { + try { + const user = await Users.findOne({ where: { email } }); + if (user && user.email !== email) { + return Promise.reject("L'adresse email existe déjà..."); + } + } catch (error) { + return console.log(error); + } + return true; + })) + .normalizeEmail(), + body('name') + .trim() + .not() + .isEmpty() + .withMessage("Vous devez avoir un nom (ou pseudo).") + .isAlphanumeric() + .withMessage("Votre nom ne peut contenir que des lettres ou/et des nombres.") + .isLength({ max: 30 }) + .withMessage("Votre nom est trop long") + .custom(async (name) => { + try { + const user = await Users.findOne({ where: { name } }); + if (user && user.name !== name) { + return Promise.reject("Le nom existe déjà..."); + } + } catch (error) { + console.log(error); + } + return true; + }), + body('isPublicEmail') + .isBoolean() + .withMessage("L'adresse email peut être public ou privé, rien d'autre."), + body('biography') + .trim() + .escape() +], usersController.putUser); + // Permet de s'inscrire UsersRouter.post('/register', [ body('email')