frontend et backend: Connexion d'un utilisateur
This commit is contained in:
parent
8c37dbaaf4
commit
76298b6087
@ -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);
|
||||
|
@ -1,12 +1,22 @@
|
||||
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);
|
||||
|
@ -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() {
|
||||
<ul className={`navbar__list ${(isActive) ? "navbar__list-active" : ""}`}>
|
||||
<NavigationLink name="Accueil" path="/" />
|
||||
<NavigationLink name="Fonctions" path="/functions" />
|
||||
|
||||
{
|
||||
(!isAuth) ?
|
||||
<Fragment>
|
||||
<NavigationLink name="S'inscrire" path="/register" />
|
||||
<NavigationLink name="Connexion" path="/login" />
|
||||
</Fragment>
|
||||
:
|
||||
<Fragment>
|
||||
<NavigationLink name="Profil" path="/profile" />
|
||||
<li className="navbar-item">
|
||||
<Link href={"/"}>
|
||||
<a onClick={logoutUser} className="navbar-link">Se déconnecter</a>
|
||||
</Link>
|
||||
</li>
|
||||
</Fragment>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
56
website/contexts/UserContext.js
Normal file
56
website/contexts/UserContext.js
Normal file
@ -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('<p class="form-success"><b>Succès:</b> Connexion réussi!</p>');
|
||||
setLoginLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setMessageLogin(`<p class="form-error"><b>Erreur:</b> ${error.response.data.message}</p>`);
|
||||
setLoginLoading(false);
|
||||
setIsAuth(false);
|
||||
setUser(null);
|
||||
});
|
||||
}
|
||||
|
||||
const logoutUser = () => {
|
||||
setUser(null);
|
||||
setIsAuth(false);
|
||||
cookies.remove('user');
|
||||
}
|
||||
|
||||
return (
|
||||
<UserContext.Provider value={{ user, loginUser, logoutUser, loginLoading, messageLogin, isAuth }}>
|
||||
{props.children}
|
||||
</UserContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserContextProvider;
|
21
website/package-lock.json
generated
21
website/package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -16,13 +16,6 @@ const Error404 = () => (
|
||||
Cette page n'existe pas! <Link href={"/"}><a>Revenir à la page d'accueil ?</a></Link>
|
||||
</p>
|
||||
</div>
|
||||
<style>
|
||||
{`
|
||||
#__next {
|
||||
padding-top: 0;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
|
@ -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 }) => (
|
||||
<Fragment>
|
||||
<UserContextProvider>
|
||||
<Header />
|
||||
<div className="content container-fluid">
|
||||
<Component {...pageProps} />
|
||||
</div>
|
||||
<Footer />
|
||||
</Fragment>
|
||||
</UserContextProvider>
|
||||
);
|
||||
|
||||
export default App;
|
@ -1,9 +1,29 @@
|
||||
import { Fragment } from 'react';
|
||||
import { Fragment, useContext, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import Link from 'next/link';
|
||||
import htmlParser from 'html-react-parser';
|
||||
import Loader from '../components/Loader';
|
||||
import HeadTag from '../components/HeadTag';
|
||||
import { UserContext } from '../contexts/UserContext';
|
||||
import '../public/css/pages/register-login.css';
|
||||
|
||||
const Login = () => {
|
||||
|
||||
const router = useRouter();
|
||||
const [inputState, setInputState] = useState({});
|
||||
const { loginUser, messageLogin, loginLoading } = useContext(UserContext);
|
||||
|
||||
const handleChange = () => {
|
||||
const inputStateNew = { ...inputState };
|
||||
inputStateNew[event.target.name] = event.target.value;
|
||||
setInputState(inputStateNew);
|
||||
}
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
loginUser(inputState);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<HeadTag
|
||||
@ -14,26 +34,40 @@ const Login = () => {
|
||||
<div className="row Register-Login__row justify-content-center">
|
||||
<div className="col-20">
|
||||
<h1 className="Register-Login__title">Se connecter</h1>
|
||||
<form>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form-group">
|
||||
<label className="form-label" htmlFor="name">Email :</label>
|
||||
<input type="email" name="email" id="email" className="form-control" placeholder="email@gmail.com" />
|
||||
<label className="form-label" htmlFor="email">Email :</label>
|
||||
<input onChange={handleChange} type="email" name="email" id="email" className="form-control" placeholder="email@gmail.com" />
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="form-label" htmlFor="name">Mot de passe :</label>
|
||||
<input type="password" name="password" id="password" className="form-control" placeholder="******" />
|
||||
<label className="form-label" htmlFor="password">Mot de passe :</label>
|
||||
<input onChange={handleChange} type="password" name="password" id="password" className="form-control" placeholder="******" />
|
||||
<p>
|
||||
<Link href={"/register"}>
|
||||
<a className="Register-Login__Forgot-password">Mot de passe oublié ?</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="form-group text-center">
|
||||
<button type="submit" className="btn btn-dark">Envoyer</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="form-result text-center"></div>
|
||||
<div className="form-result text-center">
|
||||
{(router.query.isConfirmed !== undefined) && <p className="form-success"><b>Succès:</b> Votre compte a bien été confirmé, vous pouvez maintenant vous connectez!</p>}
|
||||
{
|
||||
(loginLoading) ?
|
||||
<Loader />
|
||||
:
|
||||
htmlParser(messageLogin)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
@ -12,3 +12,11 @@
|
||||
.Register-Login__title {
|
||||
text-align: center;
|
||||
}
|
||||
.Register-Login__Forgot-password {
|
||||
color: var(--text-color);
|
||||
font-size: 16px;
|
||||
}
|
||||
.Register-Login__Forgot-password:hover {
|
||||
color: var(--important);
|
||||
text-decoration: none;
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
function redirect(ctx, path) {
|
||||
if (ctx.res) {
|
||||
ctx.res.writeHead(302, { Location: path });
|
||||
ctx.res.end();
|
||||
} else {
|
||||
document.location.pathname = path;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = redirect;
|
Reference in New Issue
Block a user