From 76298b6087d5cbc8c76bb49124e808132d9c447e Mon Sep 17 00:00:00 2001 From: Divlo Date: Mon, 6 Apr 2020 16:46:03 +0200 Subject: [PATCH] frontend et backend: Connexion d'un utilisateur --- api/controllers/users.js | 11 +++- api/routes/users.js | 20 ++++++-- website/components/Header/Header.js | 23 +++++++-- website/contexts/UserContext.js | 56 +++++++++++++++++++++ website/package-lock.json | 21 ++++++++ website/package.json | 3 +- website/pages/404.js | 7 --- website/pages/_app.js | 8 +-- website/pages/login.js | 48 +++++++++++++++--- website/public/css/pages/register-login.css | 8 +++ website/utils/redirect.js | 10 ++-- 11 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 website/contexts/UserContext.js diff --git a/api/controllers/users.js b/api/controllers/users.js index 8123c9e..189a473 100644 --- a/api/controllers/users.js +++ b/api/controllers/users.js @@ -35,8 +35,12 @@ exports.register = async (req, res, next) => { exports.login = async (req, res, next) => { const { email, password } = req.body; + const errors = validationResult(req); + if (!errors.isEmpty()) { + return errorHandling(next, { message: errors.array()[0].msg, statusCode: 400 }); + } try { - const user = await Users.findOne({ where: { email, isConfirmed: true } }); + const user = await Users.findOne({ where: { email } }); if (!user) { return errorHandling(next, { message: "Le mot de passe ou l'adresse email n'est pas valide.", statusCode: 400 }); } @@ -44,6 +48,9 @@ exports.login = async (req, res, next) => { if (!isEqual) { return errorHandling(next, { message: "Le mot de passe ou l'adresse email n'est pas valide.", statusCode: 400 }); } + if (!user.isConfirmed) { + return errorHandling(next, { message: "Vous devez valider votre adresse email pour votre première connexion.", statusCode: 400 }); + } const token = jwt.sign({ email: user.email, userId: user.id }, JWT_SECRET, { expiresIn: '1h' }); @@ -67,7 +74,7 @@ exports.confirmEmail = async (req, res, next) => { user.tempToken = null; user.isConfirmed = true; await user.save(); - return res.redirect(`${FRONT_END_HOST}/login`); + return res.redirect(`${FRONT_END_HOST}/login?isConfirmed=true`); } catch (error) { console.log(error); errorHandling(next, serverError); diff --git a/api/routes/users.js b/api/routes/users.js index d9c763f..b8a4d73 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -1,12 +1,22 @@ -const { Router } = require('express'); -const { body } = require('express-validator'); -const usersController = require('../controllers/users'); -const Users = require('../models/users'); +const { Router } = require('express'); +const { body } = require('express-validator'); +const usersController = require('../controllers/users'); +const { requiredFields } = require('../assets/config/errors'); +const Users = require('../models/users'); const UsersRouter = Router(); // Permet de se connecter -UsersRouter.post('/login', usersController.login); +UsersRouter.post('/login', [ + body('email') + .not() + .isEmpty() + .withMessage(requiredFields.message), + body('password') + .not() + .isEmpty() + .withMessage(requiredFields.message) +], usersController.login); // TODO: Récupère les informations public d'un profil // UsersRouter.get('/profile/:userName', usersController.getUserInfo); diff --git a/website/components/Header/Header.js b/website/components/Header/Header.js index 88acc02..b11027d 100644 --- a/website/components/Header/Header.js +++ b/website/components/Header/Header.js @@ -1,10 +1,12 @@ -import { useState } from 'react'; +import { Fragment, useState, useContext } from 'react'; +import { UserContext } from '../../contexts/UserContext'; import Link from 'next/link'; import NavigationLink from './NavigationLink'; import './Header.css'; export default function Header() { + const { isAuth, logoutUser } = useContext(UserContext); const [isActive, setIsActive] = useState(false); const toggleNavbar = () => { @@ -33,8 +35,23 @@ export default function Header() { diff --git a/website/contexts/UserContext.js b/website/contexts/UserContext.js new file mode 100644 index 0000000..77617b8 --- /dev/null +++ b/website/contexts/UserContext.js @@ -0,0 +1,56 @@ +import { createContext, useState, useEffect } from 'react'; +import Cookies from "universal-cookie"; +import api from '../utils/api'; + +const cookies = new Cookies(); + +export const UserContext = createContext(); + +function UserContextProvider(props) { + + const [user, setUser] = useState(null); + const [isAuth, setIsAuth] = useState(false); + const [loginLoading, setLoginLoading] = useState(false); + const [messageLogin, setMessageLogin] = useState(""); + + useEffect(() => { + const user = cookies.get('user'); + setUser(user); + if (user != undefined) { + setIsAuth(true); + } + }, []); + + const loginUser = ({ email, password }) => { + setLoginLoading(true); + api.post('/users/login', { email, password }) + .then((response) => { + const user = response.data; + cookies.set('user', user); + setUser(user); + setIsAuth(true); + setMessageLogin('

Succès: Connexion réussi!

'); + setLoginLoading(false); + }) + .catch((error) => { + setMessageLogin(`

Erreur: ${error.response.data.message}

`); + setLoginLoading(false); + setIsAuth(false); + setUser(null); + }); + } + + const logoutUser = () => { + setUser(null); + setIsAuth(false); + cookies.remove('user'); + } + + return ( + + {props.children} + + ); +} + +export default UserContextProvider; \ No newline at end of file diff --git a/website/package-lock.json b/website/package-lock.json index b7273ce..970c778 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -1400,11 +1400,21 @@ "resolved": "https://registry.npmjs.org/@next/polyfill-nomodule/-/polyfill-nomodule-9.3.2.tgz", "integrity": "sha512-kEa7v3trZmW6iWeTJrhg+ZsE9njae7mLkgyZB5M1r975JHr5PQ69B5aX7hrEAj7aAJYvCKETgAczx4gGR8MOzQ==" }, + "@types/cookie": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", + "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" + }, "@types/domhandler": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@types/domhandler/-/domhandler-2.4.1.tgz", "integrity": "sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA==" }, + "@types/object-assign": { + "version": "4.0.30", + "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", + "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=" + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -9774,6 +9784,17 @@ "imurmurhash": "^0.1.4" } }, + "universal-cookie": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.3.tgz", + "integrity": "sha512-YbEHRs7bYOBTIWedTR9koVEe2mXrq+xdjTJZcoKJK/pQaE6ni28ak2AKXFpevb+X6w3iU5SXzWDiJkmpDRb9qw==", + "requires": { + "@types/cookie": "^0.3.3", + "@types/object-assign": "^4.0.30", + "cookie": "^0.4.0", + "object-assign": "^4.1.1" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/website/package.json b/website/package.json index 2059530..1422328 100644 --- a/website/package.json +++ b/website/package.json @@ -17,7 +17,8 @@ "react": "16.13.0", "react-dom": "16.13.0", "react-swipeable-views": "^0.13.9", - "react-swipeable-views-utils": "^0.13.9" + "react-swipeable-views-utils": "^0.13.9", + "universal-cookie": "^4.0.3" }, "devDependencies": { "cross-env": "^7.0.2" diff --git a/website/pages/404.js b/website/pages/404.js index ec11efc..ef79cca 100644 --- a/website/pages/404.js +++ b/website/pages/404.js @@ -16,13 +16,6 @@ const Error404 = () => ( Cette page n'existe pas! Revenir à la page d'accueil ?

- ); diff --git a/website/pages/_app.js b/website/pages/_app.js index 2ef368e..b090e89 100644 --- a/website/pages/_app.js +++ b/website/pages/_app.js @@ -1,5 +1,4 @@ /* Libraries Imports */ -import { Fragment } from 'react'; import Router from 'next/router' import NProgress from 'nprogress'; @@ -7,6 +6,9 @@ import NProgress from 'nprogress'; import Header from '../components/Header/Header'; import Footer from '../components/Footer/Footer'; +/* Contexts Imports */ +import UserContextProvider from '../contexts/UserContext'; + /* CSS Imports */ import '../public/fonts/Montserrat/Montserrat.css'; import '../public/css/normalize.css'; @@ -19,13 +21,13 @@ Router.events.on('routeChangeComplete', () => NProgress.done()); Router.events.on('routeChangeError', () => NProgress.done()); const App = ({ Component, pageProps }) => ( - +