ajout backend UserAdmin

This commit is contained in:
Mathis 2025-04-10 20:43:45 +02:00
parent 4e35764e4c
commit 68917bbcb0
5 changed files with 187 additions and 93 deletions

View File

@ -9,7 +9,6 @@ import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.web.handler.JWTAuthHandler;
public class MainVerticle extends AbstractVerticle {
private DatabaseService databaseService;
private Router router;
@ -17,32 +16,32 @@ public class MainVerticle extends AbstractVerticle {
@Override
public void start(Promise<Void> startPromise) throws Exception {
databaseService = new DatabaseService(vertx);
// Initialisation du fournisseur JWT
JWTAuth jwtAuth = JwtAuthProvider.createJwtAuth(vertx);
// Initialisation du routeur
router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.route().handler(CorsHandler.create()
.addOrigin("*")
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.POST)
.allowedHeader("Content-Type")
.allowedHeader("Authorization"));
.addOrigin("*")
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.POST)
.allowedHeader("Content-Type")
.allowedHeader("Authorization"));
// Protéger toutes les routes commençant par "/api/"
router.route("/api/*").handler(JWTAuthHandler.create(jwtAuth));
// Initialisation des handlers de requêtes
QueryObjects queryObjects = new QueryObjects(databaseService);
QueryWeatherData queryWeather = new QueryWeatherData(databaseService);
SetObjects setObjects = new SetObjects(databaseService);
SetWeatherData setWeatherData = new SetWeatherData(databaseService);
SetWeatherData setWeatherData = new SetWeatherData(databaseService);
AuthHandler authHandler = new AuthHandler(databaseService, jwtAuth);
QueryUsers queryUsers = new QueryUsers(databaseService);
SetUser setUser = new SetUser(databaseService);
// Déclaration des routes
router.get("/objets").handler(queryObjects::getObjects);
router.get("/objet").handler(queryObjects::getParticularObject);
@ -53,22 +52,23 @@ public class MainVerticle extends AbstractVerticle {
router.get("/getRange").handler(queryWeather::getRangeData);
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
router.post("/deleteObject").handler(setObjects::deleteObject);
router.get("/users").handler(queryUsers::getUsers);
router.post("/setUserPoints").handler(setUser::setUserPoints);
// Routes d'authentification
router.post("/signup").handler(authHandler::handleSignup);
router.post("/login").handler(authHandler::handleLogin);
// Création du serveur HTTP
vertx.createHttpServer()
.requestHandler(router)
.listen(8888)
.onSuccess(server -> {
System.out.println("HTTP server started on port " + server.actualPort());
startPromise.complete();
})
.onFailure(throwable -> {
throwable.printStackTrace();
startPromise.fail(throwable);
});
.requestHandler(router)
.listen(8888)
.onSuccess(server -> {
System.out.println("HTTP server started on port " + server.actualPort());
startPromise.complete();
})
.onFailure(throwable -> {
throwable.printStackTrace();
startPromise.fail(throwable);
});
}
}

View File

@ -0,0 +1,51 @@
package com.example.starter;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Row;
public class QueryUsers {
private DatabaseService databaseService;
public QueryUsers(DatabaseService dtbS) {
this.databaseService = dtbS;
}
public void getUsers(RoutingContext context) {
databaseService.pool
.query("SELECT * FROM users;")
.execute()
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
JsonArray users = new JsonArray();
for (Row row : rows) {
int points=row.getInteger("points");
JsonObject user = new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("surname", row.getString("surname"))
.put("email", row.getString("email"))
.put("gender", row.getString("gender"))
.put("points",points);
if(points<=30){
user.put("role", "user");
}else if(points<=60){
user.put("role", "complexe");
}else if(points>=100){
user.put("role", "admin");
}
users.add(user);
}
context.response()
.putHeader("content-type", "application/json; charset=UTF-8")
.end(users.encode());
});
}
}

View File

@ -0,0 +1,48 @@
package com.example.starter;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Tuple;
public class SetUser {
private DatabaseService databaseService;
public SetUser(DatabaseService ddbs) {
this.databaseService = ddbs;
}
public void setUserPoints(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
Integer id = body.getInteger("id");
Integer points = body.getInteger("points");
databaseService.pool
.preparedQuery(
"UPDATE users SET points=? WHERE id=?")
.execute(Tuple.of(points,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());
})
.onSuccess(rows -> {
if (rows.rowCount() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
return;
}
context.response()
.putHeader("content-type", "application/json: charset=UTF-8")
.end(new JsonObject().put("success", "Les points de l'utilisateur ont bien été mis à jour").encode());
return;
});
}
}

View File

@ -1,5 +1,8 @@
import React, { useState } from "react";
import React, { useState,useEffect } from "react";
import Sidebar from "./sidebar.jsx";
import { API_BASE_URL } from "../../config.js";
import axios from "axios";
const dashboardStyles = {
mainContent: {
@ -44,35 +47,7 @@ const dashboardStyles = {
};
function Dashboard() {
// États simulés (dans une vraie application, ils viendraient d'une API ou d'un store global)
const [users, setUsers] = useState([
{
id: 1,
username: "Alice",
email: "alice@example.com",
accessLevel: "Admin",
},
{ id: 2, username: "Bob", email: "bob@example.com", accessLevel: "User" },
{
id: 3,
username: "Charlie",
email: "charlie@example.com",
accessLevel: "Guest",
},
{
id: 4,
username: "David",
email: "david@example.com",
accessLevel: "User",
},
{ id: 5, username: "Eva", email: "eva@example.com", accessLevel: "User" },
{
id: 6,
username: "Frank",
email: "frank@example.com",
accessLevel: "Admin",
},
]);
const [users, setUsers] = useState([]);
const [logs, setLogs] = useState([
{
id: 1,
@ -87,7 +62,11 @@ function Dashboard() {
timestamp: new Date().toLocaleString(),
},
]);
useEffect(() => {
axios.get(`${API_BASE_URL}/users`).then((response) => {
setUsers(response.data);
});
}, []);
return (
<div style={{ display: "flex", minHeight: "100vh" }}>
<Sidebar />
@ -118,15 +97,15 @@ function Dashboard() {
<tr>
<th style={dashboardStyles.tableHeader}>Username</th>
<th style={dashboardStyles.tableHeader}>Email</th>
<th style={dashboardStyles.tableHeader}>Access Level</th>
<th style={dashboardStyles.tableHeader}>Niveau d'accès</th>
</tr>
</thead>
<tbody>
{users.slice(0, 5).map((user) => (
<tr key={user.id}>
<td style={dashboardStyles.tableCell}>{user.username}</td>
<td style={dashboardStyles.tableCell}>{user.name}</td>
<td style={dashboardStyles.tableCell}>{user.email}</td>
<td style={dashboardStyles.tableCell}>{user.accessLevel}</td>
<td style={dashboardStyles.tableCell}>{user.role}</td>
</tr>
))}
{users.length === 0 && (

View File

@ -1,5 +1,7 @@
import React, { useState } from "react";
import React, { useState,useEffect} from "react";
import Sidebar from "./sidebar.jsx";
import { API_BASE_URL } from "../../config.js";
import axios from "axios";
const styles = {
mainContent: {
@ -46,47 +48,48 @@ const styles = {
};
function User() {
// États pour la gestion des utilisateurs, des logs, des champs du formulaire et des ajustements de points
const [users, setUsers] = useState([]);
const [logs, setLogs] = useState([]);
const [username, setUsername] = useState("");
const [name, setname] = useState("");
const [email, setEmail] = useState("");
const [pointsInput, setPointsInput] = useState({});
// Ajout d'un utilisateur
const handleAddUser = (e) => {
e.preventDefault();
const newUser = {
id: Date.now(),
username,
name,
email,
accessLevel: "User", // Niveau d'accès par défaut
accessLevel: "User",
points: 0,
};
setUsers([...users, newUser]);
logAction(username, "User added");
setUsername("");
logAction(name, "User added");
setname("");
setEmail("");
};
// Suppression d'un utilisateur (fonction présente dans script.js)
useEffect(() => {
axios.get(`${API_BASE_URL}/users`).then((response) => {
setUsers(response.data);
});
}, []);
const handleDeleteUser = (userId) => {
const user = users.find((u) => u.id === userId);
if (user) {
logAction(user.username, "User deleted");
logAction(user.name, "User deleted");
}
setUsers(users.filter((u) => u.id !== userId));
};
// Changement du niveau d'accès via le menu déroulant (fonction issue de script.js)
const handleChangeAccessLevel = (userId, newLevel) => {
setUsers(
users.map((user) => {
if (user.id === userId) {
const oldLevel = user.accessLevel;
user.accessLevel = newLevel;
const oldLevel = user.role;
user.role = newLevel;
/*ToDO*/
logAction(
user.username,
user.name,
`Access level changed from ${oldLevel} to ${newLevel}`
);
}
@ -95,26 +98,39 @@ function User() {
);
};
// Ajustement des points d'un utilisateur (fonction issue de script.js)
const handleAdjustPoints = (userId) => {
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
setUsers(
users.map((user) => {
if (user.id === userId) {
user.points += pointsToAdd;
logAction(user.username, `Points adjusted by ${pointsToAdd}`);
axios
.post(`${API_BASE_URL}/setUserPoints`, {
id:user.id,
points:user.points,
})
.then((response) => {
setMessRequete("Les points ont bien été enregistré !");
setEnregistre(true);
console.log("Ajout des points réussit :", response.data);
})
.catch((error) => {
setMessRequete("Il y a eu une erreur dans l'ajout des points!");
console.error("Erreur lors de l'ajout des points :", error);
});
logAction(user.name, `Points ajustés par ${pointsToAdd}`);
}
return user;
})
);
// Réinitialiser la valeur de l'input pour cet utilisateur
setPointsInput({ ...pointsInput, [userId]: "" });
};
// Fonction de journalisation des actions (définie dans script.js)
const logAction = (username, action) => {
const logAction = (name, action) => {
/*TODO*/
/*Ajouter le suivi dans un journal de log*/
const timestamp = new Date().toLocaleString();
setLogs([...logs, { id: Date.now(), username, action, timestamp }]);
setLogs([...logs, { id: Date.now(), name, action, timestamp }]);
};
return (
@ -129,10 +145,10 @@ function User() {
<input
style={styles.input}
type="text"
id="username"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
id="name"
placeholder="name"
value={name}
onChange={(e) => setname(e.target.value)}
required
/>
<input
@ -152,9 +168,9 @@ function User() {
<table style={styles.userTable}>
<thead>
<tr>
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
<th style={{ ...styles.thTd, ...styles.th }}>Nom</th>
<th style={{ ...styles.thTd, ...styles.th }}>Email</th>
<th style={{ ...styles.thTd, ...styles.th }}>Access Level</th>
<th style={{ ...styles.thTd, ...styles.th }}>Niveau d'accès</th>
<th style={{ ...styles.thTd, ...styles.th }}>Points</th>
<th style={{ ...styles.thTd, ...styles.th }}>Actions</th>
</tr>
@ -162,20 +178,20 @@ function User() {
<tbody>
{users.map((user) => (
<tr key={user.id}>
<td style={styles.thTd}>{user.username}</td>
<td style={styles.thTd}>{user.name}</td>
<td style={styles.thTd}>{user.email}</td>
<td style={styles.thTd}>
{/* Menu déroulant pour changer le niveau d'accès */}
<select
value={user.accessLevel}
value={user.role}
onChange={(e) =>
handleChangeAccessLevel(user.id, e.target.value)
}
style={{ padding: "5px", borderRadius: "5px" }}
>
<option value="Admin">Admin</option>
<option value="User">User</option>
<option value="Guest">Guest</option>
<option value="admin">Admin</option>
<option value="user">User</option>
<option value="complexe">Complexe</option>
</select>
</td>
<td style={styles.thTd}>
@ -225,11 +241,11 @@ function User() {
</section>
{/* Tableau des logs */}
<section className="user-logs" style={{ marginTop: "40px" }}>
<h2>Login History and Action Logs</h2>
<h2>Historique des connexions et journal des logs </h2>
<table style={styles.userTable}>
<thead>
<tr>
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
<th style={{ ...styles.thTd, ...styles.th }}>Nom</th>
<th style={{ ...styles.thTd, ...styles.th }}>Action</th>
<th style={{ ...styles.thTd, ...styles.th }}>Timestamp</th>
</tr>
@ -237,7 +253,7 @@ function User() {
<tbody>
{logs.map((log) => (
<tr key={log.id}>
<td style={styles.thTd}>{log.username}</td>
<td style={styles.thTd}>{log.name}</td>
<td style={styles.thTd}>{log.action}</td>
<td style={styles.thTd}>{log.timestamp}</td>
</tr>