diff --git a/Back-end/mvnw b/Back-end/mvnw old mode 100644 new mode 100755 diff --git a/Back-end/pom.xml b/Back-end/pom.xml index d37428b..af8af27 100644 --- a/Back-end/pom.xml +++ b/Back-end/pom.xml @@ -82,6 +82,12 @@ ${junit-jupiter.version} test + + at.favre.lib + bcrypt + 0.9.0 + + diff --git a/Back-end/src/main/java/com/example/starter/DatabaseService.java b/Back-end/src/main/java/com/example/starter/DatabaseService.java index 1985cc4..e10ab51 100644 --- a/Back-end/src/main/java/com/example/starter/DatabaseService.java +++ b/Back-end/src/main/java/com/example/starter/DatabaseService.java @@ -11,7 +11,7 @@ public class DatabaseService { public DatabaseService(Vertx vertx) { pool = JDBCPool.pool(vertx, new JDBCConnectOptions() - .setJdbcUrl("jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=UTF-8") // URL de la base de données + .setJdbcUrl("jdbc:postgresql://localhost:5432/users?useUnicode=true&characterEncoding=UTF-8") //Url de la bdd .setUser("postgres") // Nom d'utilisateur PostgreSQL .setPassword("admin"), // Mot de passe PostgreSQL new PoolOptions() diff --git a/Back-end/src/main/java/com/example/starter/MainVerticle.java b/Back-end/src/main/java/com/example/starter/MainVerticle.java index 1a26c5f..4d33ccf 100644 --- a/Back-end/src/main/java/com/example/starter/MainVerticle.java +++ b/Back-end/src/main/java/com/example/starter/MainVerticle.java @@ -1,5 +1,6 @@ package com.example.starter; +import io.vertx.ext.web.handler.BodyHandler; import io.vertx.ext.web.handler.CorsHandler; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; @@ -7,30 +8,40 @@ import io.vertx.sqlclient.Tuple; import io.vertx.core.http.HttpMethod; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; - import io.vertx.core.AbstractVerticle; import io.vertx.core.Promise; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; +import at.favre.lib.crypto.bcrypt.BCrypt; public class MainVerticle extends AbstractVerticle { private DatabaseService databaseService; + private Router router; // Déclaration du router en variable de classe @Override public void start(Promise startPromise) throws Exception { databaseService = new DatabaseService(vertx); - // Create a Router - Router router = Router.router(vertx); + + // Initialisation du router + router = Router.router(vertx); + + // Activation du BodyHandler pour pouvoir lire les requêtes JSON (important pour POST) + router.route().handler(BodyHandler.create()); + + // Gestion des CORS router.route().handler(CorsHandler.create() - .addOrigin("*") // Allow all origins - .allowedMethod(HttpMethod.GET) // Allow GET requests - .allowedMethod(HttpMethod.POST) // Allow POST requests - .allowedHeader("Content-Type") // Allow Content-Type header + .addOrigin("*") + .allowedMethod(HttpMethod.GET) + .allowedMethod(HttpMethod.POST) + .allowedHeader("Content-Type") .allowedHeader("Authorization")); + + // Déclaration des routes router.get("/objets").handler(this::getObjects); router.get("/objet").handler(this::getParticularObject); - // Create the HTTP server + router.post("/signup").handler(this::handleSignup); // Route pour l'inscription + // Création du serveur HTTP vertx.createHttpServer() .requestHandler(router) .listen(8888) @@ -44,6 +55,7 @@ public class MainVerticle extends AbstractVerticle { }); } + // Récupération des objets private void getObjects(RoutingContext context) { databaseService.pool .query("SELECT * FROM weather_objects;") @@ -60,22 +72,25 @@ public class MainVerticle extends AbstractVerticle { .end(getInfosObjects(rows).encode()); }); } + + // Récupération d'un objet spécifique private void getParticularObject(RoutingContext context) { - String id= context.request().getParam("id"); - if(id==null){ + String id = context.request().getParam("id"); + if (id == null) { context.response() - .setStatusCode(400) - .end(new JsonObject().put("error", "Paramètre 'id' manquant").encode()); + .setStatusCode(400) + .end(new JsonObject().put("error", "Paramètre 'id' manquant").encode()); return; } + databaseService.pool .preparedQuery("SELECT * FROM weather_objects WHERE id=?") .execute(Tuple.of(Integer.parseInt(id))) .onFailure(e -> { System.err.println("Erreur de récupération de la BDD :" + e.getMessage()); context.response() - .setStatusCode(500) - .end(new JsonObject().put("Erreur","Erreur de récupération de la BDD").encode()); + .setStatusCode(500) + .end(new JsonObject().put("Erreur", "Erreur de récupération de la BDD").encode()); }) .onSuccess(rows -> { if (rows.size() == 0) { @@ -83,15 +98,15 @@ public class MainVerticle extends AbstractVerticle { .setStatusCode(404) .end(new JsonObject().put("error", "Objet non trouvé").encode()); return; - } + } context.response() - .putHeader("content-type","application/json: charset=UTF-8") - .end(getInfosObjects(rows).encode()); + .putHeader("content-type", "application/json; charset=UTF-8") + .end(getInfosObjects(rows).encode()); }); - } - private JsonArray getInfosObjects(RowSet rows){ + // Convertit les résultats SQL en JSON + private JsonArray getInfosObjects(RowSet rows) { JsonArray objects = new JsonArray(); for (Row row : rows) { JsonObject object = new JsonObject() @@ -104,4 +119,51 @@ public class MainVerticle extends AbstractVerticle { } return objects; } -} \ No newline at end of file + + private void handleSignup(RoutingContext context) { + JsonObject body = context.body().asJsonObject(); + + if (body == null) { + context.response() + .setStatusCode(400) + .end(new JsonObject().put("error", "Requête invalide").encode()); + return; + } + + // Log pour vérifier le corps de la requête + System.out.println("Received body: " + body.encodePrettily()); + + String name = body.getString("name"); + String surname = body.getString("surname"); + String email = body.getString("email"); + String gender = body.getString("gender"); + String password = body.getString("password"); + + if (name == null || surname == null || email == null || gender == null || password == null) { + context.response() + .setStatusCode(400) + .end(new JsonObject().put("error", "Tous les champs sont requis").encode()); + return; + } + + // Hashage du mot de passe avec BCrypt + String hashedPassword = BCrypt.withDefaults().hashToString(12, password.toCharArray()); + + databaseService.pool + .preparedQuery("INSERT INTO users (name, surname, email, gender, password) VALUES (?, ?, ?, ?, ?)") + .execute(Tuple.of(name, surname, email, gender, hashedPassword)) + .onSuccess(result -> { + context.response() + .setStatusCode(201) + .end(new JsonObject().put("message", "Utilisateur inscrit avec succès").encode()); + }) + .onFailure(err -> { + // Log pour afficher l'erreur d'insertion + System.err.println("Erreur d'inscription : " + err.getMessage()); + context.response() + .setStatusCode(500) + .end(new JsonObject().put("error", "Erreur d'inscription").encode()); + }); +} + +} diff --git a/Front-end/src/App.jsx b/Front-end/src/App.jsx index 82b5cd9..49c675c 100644 --- a/Front-end/src/App.jsx +++ b/Front-end/src/App.jsx @@ -1,10 +1,11 @@ -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; import Home from "./pages/Home.jsx"; import About from "./pages/About.jsx"; import Gestion from "./pages/Gestion/Gestion.jsx"; import Header from "./components/Header.jsx"; import ObjectManagement from "./pages/Gestion/ObjectManagement.jsx"; import Objet from "./pages/Gestion/Objet.jsx"; +import Signup from './pages/Signup.jsx'; function App() { return ( @@ -17,6 +18,7 @@ function App() { } /> } /> } /> + } /> diff --git a/Front-end/src/components/Header.jsx b/Front-end/src/components/Header.jsx index 24c0dc0..b187e46 100644 --- a/Front-end/src/components/Header.jsx +++ b/Front-end/src/components/Header.jsx @@ -1,5 +1,6 @@ import React from "react"; import { LogIn, UserPlus } from "lucide-react"; +import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; function Header() { return ( @@ -25,10 +26,10 @@ function Header() { Connexion - + diff --git a/Front-end/src/pages/Inscription.jsx b/Front-end/src/pages/Inscription.jsx deleted file mode 100644 index 4f5c7db..0000000 --- a/Front-end/src/pages/Inscription.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; - -function Inscription() { - return ( -
-

Inscription

-
- - - - -
-
- ); -} - -export default Inscription; diff --git a/Front-end/src/pages/Signup.jsx b/Front-end/src/pages/Signup.jsx new file mode 100644 index 0000000..415634e --- /dev/null +++ b/Front-end/src/pages/Signup.jsx @@ -0,0 +1,199 @@ +import React, { useState } from 'react'; +import { Mail, User, Lock, Calendar } from 'lucide-react'; + +function Signup() { + const [formData, setFormData] = useState({ + name: '', + surname: '', + email: '', + gender: '', + password: '', + confirmPassword: '' + }); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + if (formData.password !== formData.confirmPassword) { + alert("Les mots de passe ne correspondent pas !"); + return; + } + + try { + const response = await fetch("http://localhost:8888/signup", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || "Erreur lors de l'inscription"); + } + + alert("Inscription réussie !"); + } catch (error) { + alert(error.message); + } + }; + + + return ( +
+
+

Inscription

+
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ + +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+
+ ); +} + +export default Signup; \ No newline at end of file