backend: Login/Inscription
This commit is contained in:
		| @@ -1,5 +1,10 @@ | ||||
| HOST = "http://localhost:8080" | ||||
| OpenWeatherMap_API_KEY = "" | ||||
| DB_HOST = "" | ||||
| DB_NAME = "" | ||||
| DB_USER = "" | ||||
| DB_PASS = "" | ||||
| DB_PASS = "" | ||||
| JWT_SECRET = "" | ||||
| EMAIL_HOST = "" | ||||
| EMAIL_USER = "" | ||||
| EMAIL_PASSWORD = "" | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
							
								
								
									
										53
									
								
								api/assets/config/emails.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								api/assets/config/emails.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| exports.signupEmail = (url) => ` | ||||
| <center> | ||||
|     <table border="0" cellpadding="20" cellspacing="0" height="100%" width="100%" style="background-color:#eeeeee"> | ||||
|         <tbody> | ||||
|             <tr> | ||||
|                 <td align="center" valign="top"> | ||||
|                     <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width:600px;border-radius:6px;background-color:none"> | ||||
|                         <tbody> | ||||
|                             <tr> | ||||
|                                 <td align="center" valign="top"> | ||||
|                                     <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width:600px"> | ||||
|                                         <tbody> | ||||
|                                             <tr> | ||||
|                                                 <td> | ||||
|                                                     <h1 style="font-family:Arial, Helvetica, sans-serif;font-size:28px;line-height:110%;margin-bottom:30px;margin-top:0;padding:0">FunctionProject</h1> | ||||
|                                                 </td> | ||||
|                                             </tr> | ||||
|                                         </tbody> | ||||
|                                     </table> | ||||
|                                 </td> | ||||
|                             </tr> | ||||
|                             <tr> | ||||
|                                 <td align="center" valign="top"> | ||||
|                                     <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width:600px;border-radius:6px;background-color:#ffffff"> | ||||
|                                         <tbody> | ||||
|                                             <tr> | ||||
|                                                 <td align="left" valign="top" style="line-height:150%;font-family:Helvetica;font-size:14px;color:#333333;padding:20px"> | ||||
|                                                     <h2 style="font-size:22px;line-height:28px;margin:0 0 12px 0"> | ||||
|                                                         Veuillez confirmer l'inscription | ||||
|                                                     </h2> | ||||
|                                                     <a href="${url}" style="color:#ffffff!important;display:inline-block;font-weight:500;font-size:16px;line-height:42px;font-family:'Helvetica',Arial,sans-serif;width:auto;white-space:nowrap;height:42px;margin:12px 5px 12px 0;padding:0 22px;text-decoration:none;text-align:center;border:0;border-radius:3px;vertical-align:top;background-color:#5d5d5d!important" target="_blank" rel="noopener noreferrer"><span | ||||
|                                                             style="display:inline;font-family:'Helvetica',Arial,sans-serif;text-decoration:none;font-weight:500;font-style:normal;font-size:16px;line-height:42px;border:none;background-color:#5d5d5d!important;color:#ffffff!important">Oui, je m'inscris.</span></a> | ||||
|                                                     <br> | ||||
|                                                     <div> | ||||
|                                                         <p style="padding:0 0 10px 0">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.</p> | ||||
|                                                     </div> | ||||
|                                                 </td> | ||||
|                                             </tr> | ||||
|                                         </tbody> | ||||
|                                     </table> | ||||
|                                 </td> | ||||
|                             </tr> | ||||
|                         </tbody> | ||||
|                     </table> | ||||
|                 </td> | ||||
|             </tr> | ||||
|         </tbody> | ||||
|     </table> | ||||
| </center> | ||||
| `; | ||||
							
								
								
									
										6
									
								
								api/assets/config/transporter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								api/assets/config/transporter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| const nodemailer     = require('nodemailer'); | ||||
| const { EMAIL_INFO } = require('./config'); | ||||
|  | ||||
| const transporter = nodemailer.createTransport(EMAIL_INFO); | ||||
|  | ||||
| module.exports = transporter; | ||||
							
								
								
									
										
											BIN
										
									
								
								api/assets/images/functions/default.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								api/assets/images/functions/default.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								api/assets/images/users/default.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								api/assets/images/users/default.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 9.1 KiB | 
							
								
								
									
										8
									
								
								api/controllers/admin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								api/controllers/admin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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"}); | ||||
| } | ||||
							
								
								
									
										75
									
								
								api/controllers/users.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								api/controllers/users.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										23
									
								
								api/middlewares/isAdmin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								api/middlewares/isAdmin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
|         }); | ||||
| } | ||||
							
								
								
									
										25
									
								
								api/middlewares/isAuth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								api/middlewares/isAuth.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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(); | ||||
| } | ||||
| @@ -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, | ||||
|   | ||||
							
								
								
									
										50
									
								
								api/models/users.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								api/models/users.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										136
									
								
								api/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										136
									
								
								api/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
							
								
								
									
										11
									
								
								api/routes/admin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								api/routes/admin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
							
								
								
									
										52
									
								
								api/routes/users.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								api/routes/users.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
		Reference in New Issue
	
	Block a user