Ajout du backend sur les users

This commit is contained in:
Mathis 2025-04-10 22:08:41 +02:00
parent 68917bbcb0
commit b10408f443
4 changed files with 188 additions and 200 deletions

View File

@ -54,6 +54,8 @@ public class MainVerticle extends AbstractVerticle {
router.post("/deleteObject").handler(setObjects::deleteObject);
router.get("/users").handler(queryUsers::getUsers);
router.post("/setUserPoints").handler(setUser::setUserPoints);
router.post("/deleteUser").handler(setUser::deleteUser);
// Routes d'authentification
router.post("/signup").handler(authHandler::handleSignup);
router.post("/login").handler(authHandler::handleLogin);

View File

@ -25,7 +25,7 @@ public class SetUser {
databaseService.pool
.preparedQuery(
"UPDATE users SET points=? WHERE id=?")
.execute(Tuple.of(points,id))
.execute(Tuple.of(points, id))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
@ -41,8 +41,41 @@ public class SetUser {
}
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());
.end(new JsonObject().put("success", "Les points de l'utilisateur ont bien été mis à jour")
.encode());
return;
});
}
public void deleteUser(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");
databaseService.pool
.preparedQuery("DELETE FROM users WHERE id=?")
.execute(Tuple.of(id))
.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 -> {
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", "L'utilisateur à bien été supprimé").encode());
return;
});
}
}

View File

@ -1,51 +1,8 @@
import React, { useState,useEffect } 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: {
flexGrow: 1,
padding: "20px",
},
summaryContainer: {
display: "flex",
gap: "20px",
marginBottom: "20px",
},
summaryCard: {
background: "#f4f4f4",
padding: "20px",
flex: 1,
borderRadius: "5px",
textAlign: "center",
},
table: {
width: "100%",
borderCollapse: "collapse",
},
tableHeader: {
padding: "10px",
border: "1px solid #ccc",
backgroundColor: "#f4f4f4",
},
tableCell: {
padding: "10px",
border: "1px solid #ccc",
textAlign: "left",
},
viewMoreButton: {
marginTop: "10px",
padding: "10px 15px",
backgroundColor: "#007bff",
color: "#fff",
border: "none",
borderRadius: "5px",
cursor: "pointer",
},
};
function Dashboard() {
const [users, setUsers] = useState([]);
const [logs, setLogs] = useState([
@ -62,64 +19,67 @@ 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" }}>
<div className="flex h-screen">
<Sidebar />
<main style={dashboardStyles.mainContent}>
<h1>Dashboard</h1>
<div style={dashboardStyles.summaryContainer}>
<div style={dashboardStyles.summaryCard}>
<h2>Total Users</h2>
<p>{users.length}</p>
<main className="flex-grow p-5">
<h1 className="text-2xl font-bold mb-6">Dashboard</h1>
<div className="flex gap-5 mb-6">
<div className="bg-gray-100 p-6 flex-1 rounded-lg text-center">
<h2 className="text-xl font-semibold">Total Users</h2>
<p className="text-2xl mt-2">{users.length}</p>
</div>
<div style={dashboardStyles.summaryCard}>
<h2>Dernier Log</h2>
<div className="bg-gray-100 p-6 flex-1 rounded-lg text-center">
<h2 className="text-xl font-semibold">Dernier Log</h2>
{logs.length > 0 ? (
<p>
{logs[logs.length - 1].username} -{" "}
{logs[logs.length - 1].action}
<p className="mt-2">
{logs[logs.length - 1].username} - {logs[logs.length - 1].action}
</p>
) : (
<p>Aucun log</p>
<p className="mt-2">Aucun log</p>
)}
</div>
</div>
<section>
<h2>Aperçu des Utilisateurs</h2>
<table style={dashboardStyles.table}>
<h2 className="text-xl font-semibold mb-4">Aperçu des Utilisateurs</h2>
<div className="overflow-x-auto">
<table className="min-w-full border border-gray-300">
<thead>
<tr>
<th style={dashboardStyles.tableHeader}>Username</th>
<th style={dashboardStyles.tableHeader}>Email</th>
<th style={dashboardStyles.tableHeader}>Niveau d'accès</th>
<tr className="bg-gray-100">
<th className="p-3 border text-left">Username</th>
<th className="p-3 border text-left">Email</th>
<th className="p-3 border text-left">Niveau d'accès</th>
</tr>
</thead>
<tbody>
{users.slice(0, 5).map((user) => (
<tr key={user.id}>
<td style={dashboardStyles.tableCell}>{user.name}</td>
<td style={dashboardStyles.tableCell}>{user.email}</td>
<td style={dashboardStyles.tableCell}>{user.role}</td>
<tr key={user.id} className="hover:bg-gray-50">
<td className="p-3 border text-left">{user.name}</td>
<td className="p-3 border text-left">{user.email}</td>
<td className="p-3 border text-left">{user.role}</td>
</tr>
))}
{users.length === 0 && (
<tr>
<td colSpan="3" style={dashboardStyles.tableCell}>
<td colSpan="3" className="p-3 border text-center">
Aucun utilisateur disponible
</td>
</tr>
)}
</tbody>
</table>
{/* Bouton pour accéder à la page complète */}
</div>
<button
style={dashboardStyles.viewMoreButton}
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
onClick={() => (window.location.href = "/user")}
>
Voir plus

View File

@ -1,51 +1,10 @@
import React, { useState,useEffect} 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: {
flexGrow: 1,
padding: "20px",
},
header: {
marginBottom: "20px",
},
userManagement: {
marginTop: "20px",
},
userForm: {
display: "grid",
gridTemplateColumns: "1fr 1fr auto",
gap: "10px",
marginBottom: "20px",
},
input: {
padding: "10px",
border: "1px solid #ccc",
borderRadius: "5px",
},
button: {
padding: "10px",
backgroundColor: "#28a745",
color: "white",
border: "none",
borderRadius: "5px",
cursor: "pointer",
},
userTable: {
width: "100%",
borderCollapse: "collapse",
},
thTd: {
padding: "10px",
border: "1px solid #ccc",
textAlign: "left",
},
th: {
backgroundColor: "#f4f4f4",
},
};
const thTd = "p-2 border border-gray-300 text-left";
const th = `${thTd} bg-gray-100`;
function User() {
const [users, setUsers] = useState([]);
@ -64,7 +23,7 @@ function User() {
points: 0,
};
setUsers([...users, newUser]);
logAction(name, "User added");
logAction(name, "Utilisateur ajouté");
setname("");
setEmail("");
};
@ -76,7 +35,22 @@ function User() {
const handleDeleteUser = (userId) => {
const user = users.find((u) => u.id === userId);
if (user) {
logAction(user.name, "User deleted");
axios
.post(`${API_BASE_URL}/deleteUser`, {
id: userId,
})
.then((response) => {
alert("L'utilisateur à bien été supprimé !");
console.log("L'utilisateur à été supprimé :", response.data);
window.location.reload();
})
.catch((error) => {
console.error(
"Erreur lors de la suppression de l'utilisateur :",
error
);
});
logAction(user.name, "Utilisateur supprimé");
}
setUsers(users.filter((u) => u.id !== userId));
};
@ -84,13 +58,33 @@ function User() {
const handleChangeAccessLevel = (userId, newLevel) => {
setUsers(
users.map((user) => {
if (user.id === userId) {
if (user.id === userId && newLevel!=user.role) {
const oldLevel = user.role;
user.role = newLevel;
/*ToDO*/
if (user.role === "user") {
user.points = 0;
} else if (user.role === "complexe") {
user.points = 60;
} else if (user.role === "admin") {
user.points = 100;
}
axios
.post(`${API_BASE_URL}/setUserPoints`, {
id: user.id,
points: user.points,
})
.then((response) => {
alert("Le changement de niveau a bien été enregistré !");
console.log("Changement de niveau réussit :", response.data);
})
.catch((error) => {
alert("Il y a eu une erreur dans le changement de niveau !");
console.error("Erreur lors du changement de niveau :", error);
});
logAction(
user.name,
`Access level changed from ${oldLevel} to ${newLevel}`
`Niveau d'accés changé de ${oldLevel} à ${newLevel}`
);
}
return user;
@ -103,19 +97,18 @@ function User() {
setUsers(
users.map((user) => {
if (user.id === userId) {
user.points += pointsToAdd;
user.points = pointsToAdd;
axios
.post(`${API_BASE_URL}/setUserPoints`, {
id:user.id,
points:user.points,
id: user.id,
points: user.points,
})
.then((response) => {
setMessRequete("Les points ont bien été enregistré !");
setEnregistre(true);
alert("Les points ont bien été enregistré !");
console.log("Ajout des points réussit :", response.data);
})
.catch((error) => {
setMessRequete("Il y a eu une erreur dans l'ajout des points!");
alert("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}`);
@ -134,16 +127,21 @@ function User() {
};
return (
<div style={{ display: "flex", minHeight: "100vh" }}>
<div className="flex min-h-screen">
<Sidebar />
<main style={styles.mainContent}>
<section style={styles.userManagement}>
<h1>User Management</h1>
<main className="flex-grow p-5">
<section className="mt-5">
<h1 className="text-2xl font-bold text-gray-900 mb-5">
User Management
</h1>
<p>Manage users from this panel.</p>
{/* Formulaire d'ajout d'utilisateur */}
<form style={styles.userForm} onSubmit={handleAddUser}>
<form
className="gap-3 mb-5 grid grid-cols-[1fr_1fr_auto]"
onSubmit={handleAddUser}
>
<input
style={styles.input}
className="p-3 border rounded-md"
type="text"
id="name"
placeholder="name"
@ -152,7 +150,7 @@ function User() {
required
/>
<input
style={styles.input}
className="p-3 border rounded-md"
type="email"
id="email"
placeholder="Email"
@ -160,49 +158,50 @@ function User() {
onChange={(e) => setEmail(e.target.value)}
required
/>
<button style={styles.button} type="submit">
Add User
<button
className="p-3 bg-green-600 text-white border-none rounded-md "
type="submit"
>
Ajouter utilisateur
</button>
</form>
{/* Tableau des utilisateurs */}
<table style={styles.userTable}>
<table className="w-full">
<thead>
<tr>
<th style={{ ...styles.thTd, ...styles.th }}>Nom</th>
<th style={{ ...styles.thTd, ...styles.th }}>Email</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>
<th className={`${th}`}>Nom</th>
<th className={`${th}`}>Email</th>
<th className={`${th}`}>Niveau d'accès</th>
<th className={`${th}`}>Points</th>
<th className={`${th}`}>Actions</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id}>
<td style={styles.thTd}>{user.name}</td>
<td style={styles.thTd}>{user.email}</td>
<td style={styles.thTd}>
<td className={`${thTd}`}>{user.name}</td>
<td className={`${thTd}`}>{user.email}</td>
<td className={`${thTd}`}>
{/* Menu déroulant pour changer le niveau d'accès */}
<select
value={user.role}
onChange={(e) =>
handleChangeAccessLevel(user.id, e.target.value)
}
style={{ padding: "5px", borderRadius: "5px" }}
className="p-2 rounded-md"
>
<option value="admin">Admin</option>
<option value="user">User</option>
<option value="complexe">Complexe</option>
</select>
</td>
<td style={styles.thTd}>
<span>{user.points}</span>
<td className={`${thTd}`}>
{/* Input et bouton pour ajuster les points */}
<input
className="border ml-4 w-16"
type="number"
min="0"
style={{ width: "60px", marginLeft: "10px" }}
placeholder="Adjust"
value={pointsInput[user.id] || ""}
value={pointsInput[user.id] || user.points}
onChange={(e) =>
setPointsInput({
...pointsInput,
@ -211,27 +210,19 @@ function User() {
}
/>
<button
style={{
...styles.button,
padding: "5px 10px",
marginLeft: "5px",
}}
className="p-2 bg-green-600 text-white border-none rounded-md"
onClick={() => handleAdjustPoints(user.id)}
>
Adjust
Changer
</button>
</td>
<td style={styles.thTd}>
<td className={`${thTd}`}>
{/* Bouton de suppression */}
<button
style={{
...styles.button,
backgroundColor: "#dc3545",
padding: "5px 10px",
}}
className="p-2 bg-red-600 text-white border-none rounded-md"
onClick={() => handleDeleteUser(user.id)}
>
Delete
Supprimer
</button>
</td>
</tr>
@ -240,22 +231,24 @@ function User() {
</table>
</section>
{/* Tableau des logs */}
<section className="user-logs" style={{ marginTop: "40px" }}>
<h2>Historique des connexions et journal des logs </h2>
<table style={styles.userTable}>
<section className="user-logs mt-10">
<h2 className="text-2xl font-bold text-gray-900 mb-5">
Historique des connexions et journal des logs{" "}
</h2>
<table className="w-full">
<thead>
<tr>
<th style={{ ...styles.thTd, ...styles.th }}>Nom</th>
<th style={{ ...styles.thTd, ...styles.th }}>Action</th>
<th style={{ ...styles.thTd, ...styles.th }}>Timestamp</th>
<th className={`${th}`}>Nom</th>
<th className={`${th}`}>Action</th>
<th className={`${th}`}>Timestamp</th>
</tr>
</thead>
<tbody>
{logs.map((log) => (
<tr key={log.id}>
<td style={styles.thTd}>{log.name}</td>
<td style={styles.thTd}>{log.action}</td>
<td style={styles.thTd}>{log.timestamp}</td>
<td className={`${thTd}`}>{log.name}</td>
<td className={`${thTd}`}>{log.action}</td>
<td className={`${thTd}`}>{log.timestamp}</td>
</tr>
))}
</tbody>