diff --git a/api/.env.example b/api/.env.example index 9ab37e8..570e038 100644 --- a/api/.env.example +++ b/api/.env.example @@ -1,5 +1,10 @@ +HOST = "http://localhost:8080" OpenWeatherMap_API_KEY = "" DB_HOST = "" DB_NAME = "" DB_USER = "" -DB_PASS = "" \ No newline at end of file +DB_PASS = "" +JWT_SECRET = "" +EMAIL_HOST = "" +EMAIL_USER = "" +EMAIL_PASSWORD = "" \ No newline at end of file diff --git a/api/app.js b/api/app.js index 4fb5494..cae56c7 100644 --- a/api/app.js +++ b/api/app.js @@ -22,6 +22,8 @@ app.use(express.json()); app.use('/images', express.static(path.join(__dirname, "assets", "images"))); app.use('/functions', require('./routes/functions')); app.use('/categories', require('./routes/categories')); +app.use('/users', require('./routes/users')); +app.use('/admin', require('./routes/admin')); /* Errors Handling */ app.use((_req, _res, next) => errorHandling(next, { statusCode: 404, message: "La route n'existe pas!" })); // 404 diff --git a/api/assets/config/config.js b/api/assets/config/config.js index a01ae23..5942a2e 100644 --- a/api/assets/config/config.js +++ b/api/assets/config/config.js @@ -1,5 +1,6 @@ const config = { PORT: process.env.PORT || 8080, + HOST: process.env.HOST, WEATHER_API_KEY: process.env.OpenWeatherMap_API_KEY, DATABASE: { host: process.env.DB_HOST, @@ -7,6 +8,16 @@ const config = { user: process.env.DB_USER, password: process.env.DB_PASS }, + JWT_SECRET: process.env.JWT_SECRET, + EMAIL_INFO: { + host: process.env.EMAIL_HOST, + port: 465, + secure: true, // true for 465, false for other ports + auth: { + user: process.env.EMAIL_USER, + pass: process.env.EMAIL_PASSWORD + } + } }; module.exports = config; \ No newline at end of file diff --git a/api/assets/config/emails.js b/api/assets/config/emails.js new file mode 100644 index 0000000..c2d3de6 --- /dev/null +++ b/api/assets/config/emails.js @@ -0,0 +1,53 @@ +exports.signupEmail = (url) => ` +
+ + + + + + +
+ + + + + + + + + +
+ + + + + + +
+

FunctionProject

+
+
+ + + + + + +
+

+ Veuillez confirmer l'inscription +

+ Oui, je m'inscris. +
+
+

Si vous avez reçu ce message + par erreur, il suffit de le supprimer. Vous ne serez pas + inscrit si vous ne cliquez pas sur le lien de + confirmation ci-dessus.

+
+
+
+
+
+`; \ No newline at end of file diff --git a/api/assets/config/transporter.js b/api/assets/config/transporter.js new file mode 100644 index 0000000..6f32737 --- /dev/null +++ b/api/assets/config/transporter.js @@ -0,0 +1,6 @@ +const nodemailer = require('nodemailer'); +const { EMAIL_INFO } = require('./config'); + +const transporter = nodemailer.createTransport(EMAIL_INFO); + +module.exports = transporter; \ No newline at end of file diff --git a/api/assets/images/functions/default.png b/api/assets/images/functions/default.png new file mode 100644 index 0000000..292dee9 Binary files /dev/null and b/api/assets/images/functions/default.png differ diff --git a/api/assets/images/users/default.png b/api/assets/images/users/default.png new file mode 100644 index 0000000..d3d6fbe Binary files /dev/null and b/api/assets/images/users/default.png differ diff --git a/api/controllers/admin.js b/api/controllers/admin.js new file mode 100644 index 0000000..9a31389 --- /dev/null +++ b/api/controllers/admin.js @@ -0,0 +1,8 @@ +const errorHandling = require('../assets/utils/errorHandling'); +const { serverError } = require('../assets/config/errors'); +const Users = require('../models/users'); + +exports.postFunction = (req, res, next) => { + // TODO: Pouvoir créé une fonction + res.status(200).json({ message: "test"}); +} \ No newline at end of file diff --git a/api/controllers/users.js b/api/controllers/users.js new file mode 100644 index 0000000..408fe65 --- /dev/null +++ b/api/controllers/users.js @@ -0,0 +1,75 @@ +const { validationResult } = require('express-validator'); +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); +const uuid = require('uuid'); +const errorHandling = require('../assets/utils/errorHandling'); +const { serverError, generalError } = require('../assets/config/errors'); +const { JWT_SECRET } = require('../assets/config/config'); +const transporter = require('../assets/config/transporter'); +const { EMAIL_INFO, HOST } = require('../assets/config/config'); +const { signupEmail } = require('../assets/config/emails'); +const Users = require('../models/users'); + +exports.signup = async (req, res, next) => { + const { name, email, password } = req.body; + const errors = validationResult(req); + if (!errors.isEmpty()) { + return errorHandling(next, { message: errors.array()[0].msg, statusCode: 400 }); + } + try { + const hashedPassword = await bcrypt.hash(password, 12); + const tempToken = uuid.v4(); + await Users.create({ email, name, password: hashedPassword, tempToken }); + await transporter.sendMail({ + from: `"FunctionProject" <${EMAIL_INFO.auth.user}>`, + to: email, + subject: "FunctionProject - Confirmer l'inscription", + html: signupEmail(`${HOST}/users/confirm-email/${tempToken}`) + }); + return res.status(201).json({ result: "Vous y êtes presque, veuillez vérifier votre boite d'emails pour confirmer l'inscription." }); + } catch (error) { + console.log(error); + errorHandling(next, serverError); + } +} + +exports.login = async (req, res, next) => { + const { email, password } = req.body; + try { + const user = await Users.findOne({ where: { email, confirmed: true } }); + if (!user) { + return errorHandling(next, { message: "Le mot de passe ou l'adresse email n'est pas valide.", statusCode: 400 }); + } + const isEqual = await bcrypt.compare(password, user.password); + if (!isEqual) { + return errorHandling(next, { message: "Le mot de passe ou l'adresse email n'est pas valide.", statusCode: 400 }); + } + const token = jwt.sign({ + email: user.email, userId: user.id + }, JWT_SECRET, { expiresIn: '1h' }); + return res.status(200).json({ token, id: user.id, name: user.name, email: user.email, logo: user.logo, isAdmin: user.isAdmin, createdAt: user.createdAt }); + } catch (error) { + console.log(error); + errorHandling(next, serverError); + } +} + +exports.confirmEmail = async (req, res, next) => { + const { tempToken } = req.params; + if (!tempToken) { + return errorHandling(next, generalError); + } + try { + const user = await Users.findOne({ where: { tempToken, isConfirmed: false } }); + if (!user) { + return errorHandling(next, { message: "Le token n'est pas valide.", statusCode: 400 }); + } + user.tempToken = null; + user.isConfirmed = true; + await user.save(); + return res.redirect('https://function.divlo.fr'); + } catch (error) { + console.log(error); + errorHandling(next, serverError); + } +} \ No newline at end of file diff --git a/api/middlewares/isAdmin.js b/api/middlewares/isAdmin.js new file mode 100644 index 0000000..d783a23 --- /dev/null +++ b/api/middlewares/isAdmin.js @@ -0,0 +1,23 @@ +const errorHandling = require('../assets/utils/errorHandling'); +const { serverError } = require('../assets/config/errors'); +const Users = require('../models/users'); + +module.exports = (req, _res, next) => { + if (!req.userId) { + return errorHandling(next, { message: "Vous n'êtes pas connecté.", statusCode: 401 }); + } + Users.findOne({ where: { id: req.userId } }) + .then((user) => { + if (!user) { + return errorHandling(next, { message: "Le mot de passe ou l'adresse email n'est pas valide.", statusCode: 400 }); + } + if (!user.isAdmin) { + return errorHandling(next, { message: "Vous n'êtes pas administrateur.", statusCode: 400 }); + } + next(); + }) + .catch((error) => { + console.log(error); + errorHandling(next, serverError); + }); +} \ No newline at end of file diff --git a/api/middlewares/isAuth.js b/api/middlewares/isAuth.js new file mode 100644 index 0000000..5eb3b56 --- /dev/null +++ b/api/middlewares/isAuth.js @@ -0,0 +1,25 @@ +const jwt = require('jsonwebtoken'); +const errorHandling = require('../assets/utils/errorHandling'); +const { serverError } = require('../assets/config/errors'); +const { JWT_SECRET } = require('../assets/config/config'); + +module.exports = (req, _res, next) => { + const token = req.get('Authorization'); + if (!token) { + return errorHandling(next, { message: "Vous n'êtes pas connecté.", statusCode: 401 }); + } + + let decodedToken; + try { + decodedToken = jwt.verify(token, JWT_SECRET); + } catch (error) { + return errorHandling(next, serverError); + } + + if (!decodedToken) { + return errorHandling(next, { message: "Vous n'êtes pas connecté.", statusCode: 401 }); + } + + req.userId = decodedToken.userId; + next(); +} \ No newline at end of file diff --git a/api/models/functions.js b/api/models/functions.js index dc3fb6e..4fa6bed 100644 --- a/api/models/functions.js +++ b/api/models/functions.js @@ -22,7 +22,8 @@ module.exports = sequelize.define('function', { }, image: { type: Sequelize.STRING, - allowNull: false + allowNull: false, + defaultValue: "/images/functions/default.png" }, type: { type: Sequelize.STRING, diff --git a/api/models/users.js b/api/models/users.js new file mode 100644 index 0000000..c1d794c --- /dev/null +++ b/api/models/users.js @@ -0,0 +1,50 @@ +const Sequelize = require('sequelize'); +const sequelize = require('../assets/utils/database'); + +module.exports = sequelize.define('user', { + id: { + type: Sequelize.INTEGER, + allowNull: false, + autoIncrement: true, + primaryKey: true + }, + name: { + type: Sequelize.STRING, + allowNull: false, + }, + email: { + type: Sequelize.STRING, + allowNull: false, + }, + password: { + type: Sequelize.STRING, + allowNull: false, + }, + biography: { + type: Sequelize.TEXT, + }, + logo: { + type: Sequelize.STRING, + defaultValue: "/images/users/default.png" + }, + isConfirmed: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + isPublicEmail: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + isAdmin: { + type: Sequelize.BOOLEAN, + defaultValue: false + }, + tempToken: { + type: Sequelize.TEXT, + allowNull: true + }, + tempExpirationToken: { + type: Sequelize.DATE, + allowNull: true + } +}); \ No newline at end of file diff --git a/api/package-lock.json b/api/package-lock.json index 2ed1cf1..c645886 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -96,6 +96,11 @@ "safe-buffer": "5.1.2" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", @@ -163,6 +168,11 @@ "fill-range": "^7.0.1" } }, + "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.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -410,6 +420,14 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "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", @@ -498,6 +516,22 @@ "vary": "~1.1.2" } }, + "express-validator": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.4.0.tgz", + "integrity": "sha512-Fs+x0yDOSiUV+o5jIRloMyBxqpSzJiMM8KQW1IRVv2l49F6ATU0F9uPa+3K6vXNlLlhUjauv2FCGLFPMaNr24w==", + "requires": { + "lodash": "^4.17.15", + "validator": "^12.1.0" + }, + "dependencies": { + "validator": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-12.2.0.tgz", + "integrity": "sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ==" + } + } + }, "feature-policy": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", @@ -873,6 +907,49 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "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", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "latest-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", @@ -887,6 +964,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "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=" + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -1052,6 +1164,11 @@ "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" }, + "nodemailer": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.6.tgz", + "integrity": "sha512-/kJ+FYVEm2HuUlw87hjSqTss+GU35D4giOpdSfGp7DO+5h6RlJj7R94YaYHOkoxu1CSaM0d3WRBtCzwXrY6MKA==" + }, "nodemon": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz", @@ -1303,8 +1420,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-diff": { "version": "2.1.0", @@ -1386,6 +1502,11 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, @@ -1457,6 +1578,11 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, @@ -1624,9 +1750,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz", + "integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw==" }, "validator": { "version": "10.11.0", diff --git a/api/package.json b/api/package.json index 426d009..f77ef92 100644 --- a/api/package.json +++ b/api/package.json @@ -11,13 +11,18 @@ "license": "MIT", "dependencies": { "axios": "^0.19.2", + "bcryptjs": "^2.4.3", "cors": "^2.8.5", "express": "^4.17.1", + "express-validator": "^6.4.0", "helmet": "^3.21.3", + "jsonwebtoken": "^8.5.1", "moment": "^2.24.0", "mysql2": "^2.1.0", + "nodemailer": "^6.4.6", "sequelize": "^5.21.5", - "smart-request-balancer": "^2.1.1" + "smart-request-balancer": "^2.1.1", + "uuid": "^7.0.2" }, "devDependencies": { "dotenv": "^8.2.0", diff --git a/api/routes/admin.js b/api/routes/admin.js new file mode 100644 index 0000000..6e9cb72 --- /dev/null +++ b/api/routes/admin.js @@ -0,0 +1,11 @@ +const { Router } = require('express'); +const adminController = require('../controllers/admin'); +const isAuth = require('../middlewares/isAuth'); +const isAdmin = require('../middlewares/isAdmin'); + +const AdminRouter = Router(); + +// Permet de créé une fonction +AdminRouter.post('/functions', isAuth, isAdmin, adminController.postFunction); + +module.exports = AdminRouter; \ No newline at end of file diff --git a/api/routes/users.js b/api/routes/users.js new file mode 100644 index 0000000..d0c4879 --- /dev/null +++ b/api/routes/users.js @@ -0,0 +1,52 @@ +const { Router } = require('express'); +const { body } = require('express-validator'); +const usersController = require('../controllers/users'); +const Users = require('../models/users'); + +const UsersRouter = Router(); + +// Permet de se connecter +UsersRouter.post('/login', usersController.login); + +// Permet de s'inscrire +UsersRouter.post('/signup', [ + body('email') + .isEmail() + .withMessage("Veuillez rentré une adresse mail valide.") + .custom((async (email) => { + try { + const user = await Users.findOne({ where: { email } }); + if (user) { + return Promise.reject("L'adresse email existe déjà..."); + } + } catch (error) { + return console.log(error); + } + })) + .normalizeEmail(), + body('password') + .isLength({ min: 4 }) + .withMessage("Votre mot de passe est trop court!"), + body('name') + .trim() + .not() + .isEmpty() + .withMessage("Votre nom ne peut pas être vide.") + .isAlphanumeric() + .withMessage("Votre nom ne peut contenir que des lettres ou/et des nombres.") + .custom((async (name) => { + try { + const user = await Users.findOne({ where: { name } }); + if (user) { + return Promise.reject("Le nom existe déjà..."); + } + } catch (error) { + return console.log(error); + } + })) +], usersController.signup); + +// Confirme l'inscription +UsersRouter.get('/confirm-email/:tempToken', usersController.confirmEmail); + +module.exports = UsersRouter; \ No newline at end of file