diff --git a/backend/database/schema.sql b/backend/database/schema.sql index 9c013ed..504935c 100644 --- a/backend/database/schema.sql +++ b/backend/database/schema.sql @@ -4,12 +4,12 @@ USE eating_nam_nam; #Create tables for eating nam nam DB CREATE TABLE user ( ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT, - username VARCHAR(30) NOT NULL, - email VARCHAR(80) NOT NULL, - firstname VARCHAR(30), - lastname VARCHAR(50), + username VARCHAR(20) UNIQUE NOT NULL, + email VARCHAR(30) UNIQUE NOT NULL, + firstname VARCHAR(20), + lastname VARCHAR(20), birthdate DATE, - password VARCHAR(256) NOT NULL, + password VARCHAR(255) NOT NULL, description MEDIUMTEXT, is_admin BIT, avatar VARCHAR(200) diff --git a/backend/src/controllers/userControllers.js b/backend/src/controllers/userControllers.js index 5d92b2f..b1e559f 100644 --- a/backend/src/controllers/userControllers.js +++ b/backend/src/controllers/userControllers.js @@ -40,15 +40,34 @@ const read = async (req, res, next) => { const add = async (req, res, next) => { // Extract the user data from the request body const item = req.body; - try { - // Insert the user into the database - const insertId = await tables.user.create(item); - // Respond with HTTP 201 (Created) and the ID of the newly inserted user - res.status(201).json({ insertId }); - } catch (err) { - // Pass any errors to the error-handling middleware - next(err); + const existingUsername = await tables.user.readByUsername(item.username); + const existingEmail = await tables.user.readByEmail(item.email); + + if (existingUsername && existingEmail) { + res.status(400).json({ + message: + "Il semblerait qu'un compte soit déjà existant avec ce nom d'utilisateur et cette adresse email, essayez de vous connecter", + }); + } else if (existingUsername) { + res.status(400).json({ message: "Nom d'utilisateur déjà utilisé" }); + } else if (existingEmail) { + res + .status(400) + .json({ message: "Cette adresse mail est déjà associé avec un compte" }); + } + + if (!existingUsername && !existingEmail) { + try { + // Insert the user into the database + const insertId = await tables.user.create(item); + + // Respond with HTTP 201 (Created) and the ID of the newly inserted user + res.status(201).json({ insertId }); + } catch (err) { + // Pass any errors to the error-handling middleware + next(err); + } } }; diff --git a/backend/src/router.js b/backend/src/router.js index 8e4853d..7218493 100644 --- a/backend/src/router.js +++ b/backend/src/router.js @@ -15,6 +15,8 @@ const router = express.Router(); // Import userControllers module for handling item-related operations const UserControllers = require("./controllers/userControllers"); +const AuthControllers = require("./controllers/authControllers"); + // Import the middleware for hash password in DB when a new user register const hashPasswordMiddleware = require("./middleware/hashpassMiddleware"); @@ -22,6 +24,11 @@ router.get("/users", UserControllers.browse); // Route to get a list of items router.get("/users/:id", UserControllers.read); // Route to get a specific item by ID router.post("/users", hashPasswordMiddleware, UserControllers.add); +// Route to get specific items and block the register if they exists +router.get("/username/:username", AuthControllers.readByUsername); +router.get("/email/:email", AuthControllers.readByEmail); +router.post("/login", AuthControllers.login); + /* ************************************************************************* */ // RECIPE /* ************************************************************************* */ @@ -88,18 +95,6 @@ router.get("/users", UserControllers.browse); router.get("/recipes", RecipeControllers.browse); router.get("/tags", TagControllers.browse); -/* ************************************************************************* */ -// AUTH -/* ************************************************************************* */ - -// Import authControllers module for register and connection -const AuthControllers = require("./controllers/authControllers"); - -// Route to get specific items and block the register if they exists -router.get("/username/:username", AuthControllers.readByUsername); -router.get("/email/:email", AuthControllers.readByEmail); -router.post("/login", AuthControllers.login); - /* ************************************************************************* */ module.exports = router; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 22f773b..e356419 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,6 +11,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.14.2", + "react-toastify": "^9.1.3", "sass": "^1.69.5" }, "devDependencies": { @@ -1490,6 +1491,14 @@ "node": ">= 6" } }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4076,6 +4085,18 @@ "react-dom": ">=16.8" } }, + "node_modules/react-toastify": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "dependencies": { + "clsx": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5976,6 +5997,11 @@ } } }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -7814,6 +7840,14 @@ "react-router": "6.20.0" } }, + "react-toastify": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", + "requires": { + "clsx": "^1.1.1" + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", diff --git a/frontend/src/pages/Connexion.jsx b/frontend/src/pages/Connexion.jsx index 2a7e2cd..ed03e33 100644 --- a/frontend/src/pages/Connexion.jsx +++ b/frontend/src/pages/Connexion.jsx @@ -12,15 +12,13 @@ import { resetErrMsgPassSign, resetErrMsgPassConfSign, resetAllErrMsgSign, -} from "./services/postUserVerif"; +} from "./services/postUserValid"; import "react-toastify/dist/ReactToastify.css"; import "./style/Connexion.scss"; // Formulaires de LogIn ou SignIn function TypeOfForm({ checkbox, setCheckbox }) { - const [success, setSuccess] = useState(false); - const handleClickLogin = async (event) => { event.preventDefault(); @@ -32,6 +30,13 @@ function TypeOfForm({ checkbox, setCheckbox }) { loginErrorMsg.innerText = ""; + if (!username) { + usernameErrorMsg.innerText = "Veuillez saisir votre nom d'utilisateur"; + } + if (!password) { + passwordErrorMsg.innerText = "Veuillez saisir votre mot de passe"; + } + if (username && password) { usernameErrorMsg.innerText = ""; passwordErrorMsg.innerText = ""; @@ -52,8 +57,8 @@ function TypeOfForm({ checkbox, setCheckbox }) { // Redirection vers la page de connexion si la création réussit if (response && response.status === 200) { - const user = response.data; - console.info(user); + const userLogged = response.data; + console.info("user =", userLogged); toast.success( "Authentification réussie ! 😎 Redirection en cours..", { @@ -72,15 +77,9 @@ function TypeOfForm({ checkbox, setCheckbox }) { } } catch (err) { // Log des erreurs possibles - console.error(err); + console.info(err); } } - if (!username) { - usernameErrorMsg.innerText = "Veuillez saisir votre nom d'utilisateur"; - } - if (!password) { - passwordErrorMsg.innerText = "Veuillez saisir votre mot de passe"; - } }; // Vérifie en temps réel si le password est valide et qu'il correspond au passConf si celui-ci est renseigné @@ -93,54 +92,46 @@ function TypeOfForm({ checkbox, setCheckbox }) { // Actions réalisés au submit "Connexion" const handleClickRegister = (event) => { event.preventDefault(); - // Verification du formulaire d'inscription - isValidUsername().then((usernameIsValid) => { - // Ici avec le '.then' on attend le retour de la fonction async qui cherche dans la BDD si l'utilisateur existe - // La fonction renvoie une valeur 'true' ou 'false' contenu dans "usernameIsValid" - - isValidEmail().then((emailIsValid) => { - // Ici avec le '.then' on attend le retour de la fonction async qui cherche dans la BDD si l'email existe - // La fonction renvoie une valeur 'true' ou 'false' contenu dans "usernameIsValid" - - // Puis le reste des verifications s'exécute et renvoient une valeur 'true' ou 'false' - const passwordIsValid = isValidPassword(); - const passConfIsValid = isPassMatch(); + // Verification du formulaire d'inscription + const usernameIsValid = isValidUsername(); + const emailIsValid = isValidEmail(); + const passwordIsValid = isValidPassword(); + const passConfIsValid = isPassMatch(); - // Si tout est OK (true) on exécute la suite du code - if ( - usernameIsValid && - emailIsValid && - passwordIsValid && - passConfIsValid - ) { - // Récuperation des valeurs du formulaire - const username = document.querySelector("#username"); - const email = document.querySelector("#email"); - const password = document.querySelector("#password"); + // Si tout est OK (true) on exécute la suite du code + if (usernameIsValid && emailIsValid && passwordIsValid && passConfIsValid) { + // Récuperation des valeurs du formulaire + const username = document.querySelector("#username").value; + const email = document.querySelector("#email").value; + const password = document.querySelector("#password").value; - // Création de l'objet contenant la data à envoyer - const formData = { - username: username.value, - email: email.value, - password: password.value, - }; + // Création de l'objet contenant la data à envoyer + const formData = { + username, + email, + password, + }; - // Envoie des données vers notre API - axios - .post(`${import.meta.env.VITE_BACKEND_URL}/api/users`, formData) - .then(() => setSuccess(!success)) - .catch((err) => console.error(err)); + // Envoie des données vers notre API + axios + .post(`${import.meta.env.VITE_BACKEND_URL}/api/users`, formData) + .then((res) => { + if (res.status === 201) { + // Message pop-up de succès + toast.success("Votre compte à bien été créé ! 😎"); - // Rechargement de la page - toast.success("Votre compte à bien été créé ! 😎"); - document.getElementsByTagName("form")[2].email.value = ""; - if (!checkbox) setCheckbox(true); - else setCheckbox(false); - } - }); - console.error("Saisie du formulaire incorrect"); - }); + // Redirection sur le login en gardant la valeur de username + document.getElementsByTagName("form")[2].email.value = ""; + if (!checkbox) setCheckbox(true); + console.info("response =", res); + } + }) + .catch((err) => { + // Affiche un pop-up du message d'erreur + toast.error(err.response.data.message); + }); + } else toast.error("Saisie du formulaire incorrect 🫠"); }; // Affiche soit un formulaire de connexion soit d'inscription @@ -165,7 +156,7 @@ function TypeOfForm({ checkbox, setCheckbox }) { ) : ( // Formulaire d'inscription - // Les fonctions 'onBlur' et 'onFocus' permettent de vérifier et d'afficher "en temps réel" si il y a des erreurs lors de la saisie du formaulaire + // Les fonctions 'onBlur' et 'onFocus' permettent de vérifier et d'afficher "en temps réel" si il y a des erreurs lors de la saisie du formulaire
{/* Label et champ du nom d'utilisateur */} diff --git a/frontend/src/pages/services/getUserVerif.js b/frontend/src/pages/services/getUserVerif.js deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/pages/services/postUserVerif.js b/frontend/src/pages/services/postUserValid.js similarity index 73% rename from frontend/src/pages/services/postUserVerif.js rename to frontend/src/pages/services/postUserValid.js index 4ed2e74..3df4a22 100644 --- a/frontend/src/pages/services/postUserVerif.js +++ b/frontend/src/pages/services/postUserValid.js @@ -1,6 +1,4 @@ -import axios from "axios"; - -async function isValidUsername() { +function isValidUsername() { // Récupère le champ username et la balise erreur correspondante const username = document.querySelector("#username").value; const usernameErrorMsg = document.querySelector("#username-error"); @@ -11,28 +9,12 @@ async function isValidUsername() { "Le nom d'utilisateur doit contenir 5 à 20 caractères."; return false; } - // Verifie si l'utilisateur existe dans la BDD - try { - const response = await axios.get( - `${import.meta.env.VITE_BACKEND_URL}/api/username/${username}` - ); - // Si oui : retourne un mdg d'erreur dans la balise, et la fonction renvoie false - if (response.data.username === username) { - usernameErrorMsg.innerText = "Le nom d'utilisateur est déjà utilisé"; - return false; - } - } catch (error) { - // Si on obtient une erreur 404, cela signifie que l'utilisateur n'existe pas dans la BDD - if (error.response.status === 404) { - usernameErrorMsg.innerText = ""; // Aucune erreur n'est affichée dans ce cas - } - } // Sinon la fonction renvoie 'true' sans message d'erreur pour indiquer le username comme OK return true; } -async function isValidEmail() { +function isValidEmail() { // Récupère le champ email et la balise erreur correspondante const email = document.querySelector("#email").value; const emailErrorMsg = document.querySelector("#email-error"); @@ -49,24 +31,6 @@ async function isValidEmail() { return false; } - // Verifie si l'email existe dans la BDD - try { - const response = await axios.get( - `${import.meta.env.VITE_BACKEND_URL}/api/email/${email}` - ); - // Si oui : retourne un msg d'erreur dans la balise, et la fonction renvoie false - if (response.data.email === email) { - emailErrorMsg.innerText = - "Cette adresse email est déjà utilisé avec un autre compte."; - console.info(emailErrorMsg.innerText); - return false; - } - } catch (error) { - // Si on obtient une erreur 404, cela signifie que l'email n'existe pas dans la BDD - if (error.response.status === 404) { - emailErrorMsg.innerText = ""; // Aucune erreur n'est affichée dans ce cas - } - } // Sinon la fonction renvoie 'true' sans message d'erreur pour indiquer le mail comme OK return true; }