From 366654a7966e1a8b381f5f23a2f888b60e1734b1 Mon Sep 17 00:00:00 2001 From: lionsdev Date: Sun, 15 Feb 2026 14:41:13 +0000 Subject: [PATCH] refactoring --- .gitignore | 130 --- pom.xml | 23 +- .../manager/client/api/AuditRestClient.java | 63 +- .../manager/client/api/HealthRestClient.java | 3 + .../manager/client/api/RoleRestClient.java | 65 +- .../manager/client/api/SyncRestClient.java | 6 +- .../manager/client/api/UserRestClient.java | 94 +- .../client/filter/AuthHeaderFactory.java | 45 +- .../client/service/AuditServiceClient.java | 113 +-- .../service/RealmAssignmentServiceClient.java | 96 +- .../client/service/RealmServiceClient.java | 22 +- .../client/service/RoleServiceClient.java | 149 +-- .../client/service/SyncServiceClient.java | 82 +- .../client/service/UserServiceClient.java | 163 +--- .../client/view/AuditConsultationBean.java | 111 +-- .../manager/client/view/DashboardBean.java | 383 +++----- .../client/view/FreyaShowcaseBean.java | 285 ++++++ .../client/view/RealmAssignmentBean.java | 99 +- .../manager/client/view/RoleGestionBean.java | 116 +-- .../client/view/SessionMonitorBean.java | 8 +- .../client/view/SyncDashboardBean.java | 129 +++ .../manager/client/view/UserCreationBean.java | 80 +- .../manager/client/view/UserListBean.java | 373 +++---- .../manager/client/view/UserProfilBean.java | 85 +- .../manager/client/view/UserSessionBean.java | 107 +- src/main/resources/META-INF/faces-config.xml | 31 - .../resources/META-INF/resources/index.xhtml | 58 ++ .../pages/user-manager/audit/logs.xhtml | 499 ++++------ .../pages/user-manager/dashboard.xhtml | 498 +++------- .../pages/user-manager/freya-showcase.xhtml | 918 ++++++++++++++++++ .../pages/user-manager/roles/assign.xhtml | 14 + .../pages/user-manager/roles/list.xhtml | 568 +++-------- .../pages/user-manager/settings.xhtml | 147 ++- .../pages/user-manager/sync/dashboard.xhtml | 125 ++- .../pages/user-manager/users/create.xhtml | 556 ++++------- .../pages/user-manager/users/edit.xhtml | 333 +------ .../pages/user-manager/users/list.xhtml | 535 ++-------- .../pages/user-manager/users/profile.xhtml | 99 +- .../pages/user-manager/users/view.xhtml | 215 +--- .../components/audit/audit-log-row.xhtml | 155 +-- .../components/audit/audit-stats-card.xhtml | 119 +-- .../templates/components/layout/menu.xhtml | 100 +- .../components/layout/page-header.xhtml | 93 +- .../templates/components/layout/topbar.xhtml | 321 ++---- .../role-assignment-content.xhtml | 170 ++++ .../role-management/role-assignment.xhtml | 209 +--- .../role-management/role-card.xhtml | 222 +++-- .../role-management/role-form-content.xhtml | 238 +++-- .../shared/buttons/button-user-action.xhtml | 158 +-- .../shared/cards/kpi-card-content.xhtml | 125 +-- .../shared/forms/user-form-field.xhtml | 207 ++-- .../shared/tables/user-data-table.xhtml | 189 ++-- .../user-management/user-actions.xhtml | 457 +++------ .../user-management/user-card.xhtml | 183 ++-- .../user-management/user-form-content.xhtml | 429 ++++---- .../user-management/user-role-badge.xhtml | 116 +-- .../user-management/user-roles-manager.xhtml | 81 ++ .../user-search-bar-content.xhtml | 281 +++--- .../resources/templates/main-template.xhtml | 101 +- src/main/resources/application-dev.properties | 63 +- .../resources/application-prod.properties | 62 +- src/main/resources/application.properties | 130 +-- .../view/AuditConsultationBeanTest.java | 50 +- .../client/view/DashboardBeanTest.java | 24 +- .../client/view/RealmAssignmentBeanTest.java | 46 +- .../client/view/RoleGestionBeanTest.java | 53 +- .../client/view/UserCreationBeanTest.java | 14 +- .../manager/client/view/UserListBeanTest.java | 20 +- .../client/view/UserProfilBeanTest.java | 27 +- 69 files changed, 5196 insertions(+), 6673 deletions(-) delete mode 100644 .gitignore create mode 100644 src/main/java/dev/lions/user/manager/client/view/FreyaShowcaseBean.java create mode 100644 src/main/java/dev/lions/user/manager/client/view/SyncDashboardBean.java create mode 100644 src/main/resources/META-INF/resources/index.xhtml create mode 100644 src/main/resources/META-INF/resources/pages/user-manager/freya-showcase.xhtml create mode 100644 src/main/resources/META-INF/resources/pages/user-manager/roles/assign.xhtml create mode 100644 src/main/resources/META-INF/resources/templates/components/role-management/role-assignment-content.xhtml create mode 100644 src/main/resources/META-INF/resources/templates/components/user-management/user-roles-manager.xhtml diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b813c65..0000000 --- a/.gitignore +++ /dev/null @@ -1,130 +0,0 @@ -# ============================================================================ -# Lions User Manager - Client Quarkus PrimeFaces Freya - .gitignore -# ============================================================================ - -# Maven -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar - -# Build artifacts -*.jar -*.war -*.ear -*.class -*.idx - -# Eclipse -.project -.classpath -.settings/ -.metadata/ -bin/ - -# IntelliJ IDEA -.idea/ -*.iml -*.iws -*.ipr -out/ - -# NetBeans -nbproject/ -nbbuild/ -nbdist/ -.nb-gradle/ - -# VS Code -.vscode/ -*.code-workspace - -# Mac -.DS_Store - -# Windows -Thumbs.db -ehthumbs.db -Desktop.ini - -# Logs -logs/ -*.log -*.log.* -hs_err_pid*.log - -# Quarkus -.quarkus/ -quarkus-app/ -quarkus-run.jar -quarkus-*.dat - -# Temporary files -*.tmp -*.bak -*.swp -*~ -*.orig - -# Test files and reports -test_output*.txt -surefire-reports/ -failsafe-reports/ -*.dump -*.dumpstream - -# Test coverage -.jacoco/ -jacoco.exec -coverage/ -target/site/jacoco/ - -# Application specific -application-local.properties -application-*.local.properties - -# Configuration files with sensitive data -*.local.json - -# Token and authentication files -token.json -token.txt -*.token - -# Generated sources -generated-sources/ -generated-test-sources/ - -# Maven status -maven-status/ - -# Node modules (si utilisé pour le build frontend) -node_modules/ - -# Build metrics -build-metrics.json - -# Quarkus Dev Services -.devservices/ - -# IDE specific -*.sublime-project -*.sublime-workspace - -# OS specific -.DS_Store? -._* -.Spotlight-V100 -.Trashes - -# Environment files -.env -.env.local -.env.*.local - diff --git a/pom.xml b/pom.xml index 864ef71..2518315 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,6 @@ lions-user-manager-client-quarkus-primefaces-freya - 1.0.1 jar Lions User Manager - Client (Quarkus + PrimeFaces Freya) @@ -22,7 +21,6 @@ dev.lions.user.manager lions-user-manager-server-api - 1.0.0 @@ -42,6 +40,11 @@ quarkus-oidc + + io.quarkus + quarkus-rest-client-oidc-token-propagation + + io.quarkus quarkus-security @@ -67,12 +70,6 @@ 5.0.0 - - - dev.lions - primefaces-freya-extension - - io.quarkiverse.omnifaces @@ -100,28 +97,26 @@ - io.quarkus - quarkus-junit5-mockito + io.rest-assured + rest-assured test org.mockito mockito-core - 5.7.0 test org.mockito mockito-junit-jupiter - 5.7.0 test - io.rest-assured - rest-assured + io.quarkus + quarkus-junit5-mockito test diff --git a/src/main/java/dev/lions/user/manager/client/api/AuditRestClient.java b/src/main/java/dev/lions/user/manager/client/api/AuditRestClient.java index 82170a1..72f1a95 100644 --- a/src/main/java/dev/lions/user/manager/client/api/AuditRestClient.java +++ b/src/main/java/dev/lions/user/manager/client/api/AuditRestClient.java @@ -1,52 +1,55 @@ package dev.lions.user.manager.client.api; +import dev.lions.user.manager.client.filter.AuthHeaderFactory; import dev.lions.user.manager.dto.audit.AuditLogDTO; import dev.lions.user.manager.enums.audit.TypeActionAudit; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import java.util.List; import java.util.Map; @RegisterRestClient(configKey = "user-api") +@RegisterClientHeaders(AuthHeaderFactory.class) @Path("/api/audit") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public interface AuditRestClient { - @GET - List searchLogs( - @QueryParam("acteur") String acteur, - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin, - @QueryParam("typeAction") TypeActionAudit typeAction, - @QueryParam("ressourceType") String ressourceType, - @QueryParam("succes") Boolean succes, - @QueryParam("page") int page, - @QueryParam("pageSize") int pageSize); + @GET + List searchLogs( + @QueryParam("acteur") String acteur, + @QueryParam("dateDebut") String dateDebut, + @QueryParam("dateFin") String dateFin, + @QueryParam("typeAction") TypeActionAudit typeAction, + @QueryParam("ressourceType") String ressourceType, + @QueryParam("succes") Boolean succes, + @QueryParam("page") int page, + @QueryParam("pageSize") int pageSize); - @GET - @Path("/stats/actions") - Map getActionStatistics( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin); + @GET + @Path("/stats/actions") + Map getActionStatistics( + @QueryParam("dateDebut") String dateDebut, + @QueryParam("dateFin") String dateFin); - @GET - @Path("/stats/activity") - Map getUserActivityStatistics( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin); + @GET + @Path("/stats/activity") + Map getUserActivityStatistics( + @QueryParam("dateDebut") String dateDebut, + @QueryParam("dateFin") String dateFin); - @GET - @Path("/stats/failures") - long getFailureCount( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin); + @GET + @Path("/stats/failures") + long getFailureCount( + @QueryParam("dateDebut") String dateDebut, + @QueryParam("dateFin") String dateFin); - @GET - @Path("/stats/successes") - long getSuccessCount( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin); + @GET + @Path("/stats/successes") + long getSuccessCount( + @QueryParam("dateDebut") String dateDebut, + @QueryParam("dateFin") String dateFin); } diff --git a/src/main/java/dev/lions/user/manager/client/api/HealthRestClient.java b/src/main/java/dev/lions/user/manager/client/api/HealthRestClient.java index 4963a02..9046408 100644 --- a/src/main/java/dev/lions/user/manager/client/api/HealthRestClient.java +++ b/src/main/java/dev/lions/user/manager/client/api/HealthRestClient.java @@ -1,14 +1,17 @@ package dev.lions.user.manager.client.api; +import dev.lions.user.manager.client.filter.AuthHeaderFactory; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import java.util.Map; @RegisterRestClient(configKey = "user-api") +@RegisterClientHeaders(AuthHeaderFactory.class) @Path("/api/health") @Produces(MediaType.APPLICATION_JSON) public interface HealthRestClient { diff --git a/src/main/java/dev/lions/user/manager/client/api/RoleRestClient.java b/src/main/java/dev/lions/user/manager/client/api/RoleRestClient.java index e9af811..731095a 100644 --- a/src/main/java/dev/lions/user/manager/client/api/RoleRestClient.java +++ b/src/main/java/dev/lions/user/manager/client/api/RoleRestClient.java @@ -1,57 +1,60 @@ package dev.lions.user.manager.client.api; +import dev.lions.user.manager.client.filter.AuthHeaderFactory; import dev.lions.user.manager.dto.role.RoleAssignmentDTO; import dev.lions.user.manager.dto.role.RoleDTO; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import java.util.List; @RegisterRestClient(configKey = "user-api") +@RegisterClientHeaders(AuthHeaderFactory.class) @Path("/api/roles") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public interface RoleRestClient { - @GET - @Path("/realm") - List getAllRealmRoles(@QueryParam("realm") String realmName); + @GET + @Path("/realm") + List getAllRealmRoles(@QueryParam("realm") String realmName); - @POST - @Path("/realm") - RoleDTO createRealmRole(@QueryParam("realm") String realmName, RoleDTO role); + @POST + @Path("/realm") + RoleDTO createRealmRole(@QueryParam("realm") String realmName, RoleDTO role); - @GET - @Path("/realm/{roleName}") - RoleDTO getRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName); + @GET + @Path("/realm/{roleName}") + RoleDTO getRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName); - @PUT - @Path("/realm/{roleName}") - RoleDTO updateRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName, - RoleDTO role); + @PUT + @Path("/realm/{roleName}") + RoleDTO updateRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName, + RoleDTO role); - @DELETE - @Path("/realm/{roleName}") - void deleteRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName); + @DELETE + @Path("/realm/{roleName}") + void deleteRealmRole(@PathParam("roleName") String roleName, @QueryParam("realm") String realmName); - @POST - @Path("/users/{userId}/realm-roles") - void assignRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName, - RoleAssignmentRequest request); + @POST + @Path("/users/{userId}/realm-roles") + void assignRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName, + RoleAssignmentRequest request); - @DELETE - @Path("/users/{userId}/realm-roles") - void revokeRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName, - RoleAssignmentRequest request); + @DELETE + @Path("/users/{userId}/realm-roles") + void revokeRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName, + RoleAssignmentRequest request); - @GET - @Path("/users/{userId}/realm-roles") - List getUserRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName); + @GET + @Path("/users/{userId}/realm-roles") + List getUserRealmRoles(@PathParam("userId") String userId, @QueryParam("realm") String realmName); - // Inner class for role assignment request - class RoleAssignmentRequest { - public List roleNames; - } + // Inner class for role assignment request + class RoleAssignmentRequest { + public List roleNames; + } } diff --git a/src/main/java/dev/lions/user/manager/client/api/SyncRestClient.java b/src/main/java/dev/lions/user/manager/client/api/SyncRestClient.java index 6740723..8f1700e 100644 --- a/src/main/java/dev/lions/user/manager/client/api/SyncRestClient.java +++ b/src/main/java/dev/lions/user/manager/client/api/SyncRestClient.java @@ -1,12 +1,15 @@ package dev.lions.user.manager.client.api; +import dev.lions.user.manager.client.filter.AuthHeaderFactory; import dev.lions.user.manager.dto.sync.HealthStatusDTO; import dev.lions.user.manager.dto.sync.SyncResultDTO; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterRestClient(configKey = "user-api") +@RegisterClientHeaders(AuthHeaderFactory.class) @Path("/api/sync") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @@ -22,8 +25,7 @@ public interface SyncRestClient { @POST @Path("/{realmName}/all") - SyncResultDTO syncAll(@PathParam("realmName") String realmName); // Assumant que syncAll retourne un résultat - // détaillé + SyncResultDTO syncAll(@PathParam("realmName") String realmName); @GET @Path("/health") diff --git a/src/main/java/dev/lions/user/manager/client/api/UserRestClient.java b/src/main/java/dev/lions/user/manager/client/api/UserRestClient.java index 7a8c1e7..af95cd1 100644 --- a/src/main/java/dev/lions/user/manager/client/api/UserRestClient.java +++ b/src/main/java/dev/lions/user/manager/client/api/UserRestClient.java @@ -1,73 +1,77 @@ package dev.lions.user.manager.client.api; +import dev.lions.user.manager.client.filter.AuthHeaderFactory; import dev.lions.user.manager.dto.user.UserDTO; import dev.lions.user.manager.dto.user.UserSearchResultDTO; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; import java.util.List; @RegisterRestClient(configKey = "user-api") +@RegisterClientHeaders(AuthHeaderFactory.class) @Path("/api/users") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public interface UserRestClient { - @GET - UserSearchResultDTO searchUsers( - @QueryParam("realm") String realmName, - @QueryParam("search") String searchTerm, - @QueryParam("username") String username, - @QueryParam("email") String email, - @QueryParam("prenom") String prenom, - @QueryParam("nom") String nom, - @QueryParam("enabled") Boolean enabled, - @QueryParam("page") int page, - @QueryParam("pageSize") int pageSize); + @GET + UserSearchResultDTO searchUsers( + @QueryParam("realm") String realmName, + @QueryParam("search") String searchTerm, + @QueryParam("username") String username, + @QueryParam("email") String email, + @QueryParam("prenom") String prenom, + @QueryParam("nom") String nom, + @QueryParam("enabled") Boolean enabled, + @QueryParam("page") int page, + @QueryParam("pageSize") int pageSize); - @GET - @Path("/{id}") - UserDTO getUserById(@PathParam("id") String id, @QueryParam("realm") String realmName); + @GET + @Path("/{id}") + UserDTO getUserById(@PathParam("id") String id, @QueryParam("realm") String realmName); - @POST - Response createUser(@QueryParam("realm") String realmName, UserDTO user); + @POST + Response createUser(@QueryParam("realm") String realmName, UserDTO user); - @PUT - @Path("/{id}") - UserDTO updateUser(@PathParam("id") String id, @QueryParam("realm") String realmName, UserDTO user); + @PUT + @Path("/{id}") + UserDTO updateUser(@PathParam("id") String id, @QueryParam("realm") String realmName, UserDTO user); - @DELETE - @Path("/{id}") - void deleteUser(@PathParam("id") String id, @QueryParam("realm") String realmName, - @QueryParam("hard") boolean hardDelete); + @DELETE + @Path("/{id}") + void deleteUser(@PathParam("id") String id, @QueryParam("realm") String realmName, + @QueryParam("hard") boolean hardDelete); - @PUT - @Path("/{id}/activate") - void activateUser(@PathParam("id") String id, @QueryParam("realm") String realmName); + @PUT + @Path("/{id}/activate") + void activateUser(@PathParam("id") String id, @QueryParam("realm") String realmName); - @PUT - @Path("/{id}/deactivate") - void deactivateUser(@PathParam("id") String id, @QueryParam("realm") String realmName, - @QueryParam("reason") String reason); + @PUT + @Path("/{id}/deactivate") + void deactivateUser(@PathParam("id") String id, @QueryParam("realm") String realmName, + @QueryParam("reason") String reason); - @POST - @Path("/{id}/reset-password") - void resetPassword(@PathParam("id") String id, @QueryParam("realm") String realmName, PasswordResetRequest request); + @POST + @Path("/{id}/reset-password") + void resetPassword(@PathParam("id") String id, @QueryParam("realm") String realmName, + PasswordResetRequest request); - @POST - @Path("/{id}/send-verify-email") - void sendVerificationEmail(@PathParam("id") String id, @QueryParam("realm") String realmName); + @POST + @Path("/{id}/send-verify-email") + void sendVerificationEmail(@PathParam("id") String id, @QueryParam("realm") String realmName); - @GET - @Path("/export/csv") - @Produces(MediaType.TEXT_PLAIN) - String exportUsersToCSV(@QueryParam("realm") String realmName); + @GET + @Path("/export/csv") + @Produces(MediaType.TEXT_PLAIN) + String exportUsersToCSV(@QueryParam("realm") String realmName); - // Inner class for password reset request DTO - class PasswordResetRequest { - public String password; - public boolean temporary; - } + // Inner class for password reset request DTO + class PasswordResetRequest { + public String password; + public boolean temporary; + } } diff --git a/src/main/java/dev/lions/user/manager/client/filter/AuthHeaderFactory.java b/src/main/java/dev/lions/user/manager/client/filter/AuthHeaderFactory.java index 06d29bc..33c47db 100644 --- a/src/main/java/dev/lions/user/manager/client/filter/AuthHeaderFactory.java +++ b/src/main/java/dev/lions/user/manager/client/filter/AuthHeaderFactory.java @@ -1,31 +1,25 @@ package dev.lions.user.manager.client.filter; -import jakarta.enterprise.context.ApplicationScoped; +import io.quarkus.oidc.AccessTokenCredential; +import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.ws.rs.core.MultivaluedHashMap; import jakarta.ws.rs.core.MultivaluedMap; -import org.eclipse.microprofile.jwt.JsonWebToken; import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory; import java.util.logging.Logger; /** - * Factory pour ajouter automatiquement le token OIDC Bearer - * dans les headers des requêtes REST Client vers le backend. - * - * Ce factory est nécessaire car bearer-token-propagation ne fonctionne pas - * pour les appels depuis les managed beans JSF vers le backend. - * - * @author Lions User Manager - * @version 1.0.0 + * Factory to automatically add the OIDC access token (Bearer) + * to REST Client request headers. */ -@ApplicationScoped +@RequestScoped public class AuthHeaderFactory implements ClientHeadersFactory { private static final Logger LOGGER = Logger.getLogger(AuthHeaderFactory.class.getName()); @Inject - JsonWebToken jwt; + AccessTokenCredential accessTokenCredential; @Override public MultivaluedMap update( @@ -34,17 +28,30 @@ public class AuthHeaderFactory implements ClientHeadersFactory { MultivaluedMap result = new MultivaluedHashMap<>(); + // 1. Log incoming and outgoing headers for debugging + if (incomingHeaders != null) { + LOGGER.fine("Incoming Headers: " + incomingHeaders.keySet()); + } + if (clientOutgoingHeaders != null) { + LOGGER.fine("Client Outgoing Headers: " + clientOutgoingHeaders.keySet()); + } + try { - // Vérifier si le JWT est disponible et non expiré - if (jwt != null && jwt.getRawToken() != null && !jwt.getRawToken().isEmpty()) { - String token = jwt.getRawToken(); - result.add("Authorization", "Bearer " + token); - LOGGER.fine("Token Bearer ajouté au header Authorization"); + if (accessTokenCredential != null) { + // 2. Check if the token is available + String accessToken = accessTokenCredential.getToken(); + if (accessToken != null && !accessToken.isEmpty()) { + result.add("Authorization", "Bearer " + accessToken); + LOGGER.info("Access token added to Authorization header. Token length: " + accessToken.length()); + } else { + LOGGER.warning("Access token is empty or null in AccessTokenCredential."); + } } else { - LOGGER.warning("Token JWT non disponible ou vide - impossible d'ajouter le header Authorization"); + LOGGER.warning("AccessTokenCredential is unavailable - user might not be authenticated."); } } catch (Exception e) { - LOGGER.severe("Erreur lors de l'ajout du token Bearer: " + e.getMessage()); + LOGGER.severe("Error adding Bearer token: " + e.getMessage()); + e.printStackTrace(); } return result; diff --git a/src/main/java/dev/lions/user/manager/client/service/AuditServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/AuditServiceClient.java index c393e15..b0752f7 100644 --- a/src/main/java/dev/lions/user/manager/client/service/AuditServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/AuditServiceClient.java @@ -1,115 +1,24 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.AuditResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; -import dev.lions.user.manager.dto.audit.AuditLogDTO; -import dev.lions.user.manager.enums.audit.TypeActionAudit; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - /** - * REST Client pour le service d'audit + * REST Client pour le service d'audit. + * Étend maintenant l'interface API commune définie dans server-api. */ -@Path("/api/audit") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public interface AuditServiceClient { +public interface AuditServiceClient extends AuditResourceApi { - @POST - @Path("/search") - List searchLogs( - @QueryParam("acteur") String acteurUsername, - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin, - @QueryParam("typeAction") TypeActionAudit typeAction, - @QueryParam("ressourceType") String ressourceType, - @QueryParam("succes") Boolean succes, - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("50") int pageSize - ); + // Méthodes héritées de AuditResourceApi + // Note: getLogsByActeur (FR) a été remplacé par getLogsByActor (EN) dans l'API + // commune. - @GET - @Path("/actor/{acteurUsername}") - List getLogsByActeur( - @PathParam("acteurUsername") String acteurUsername, - @QueryParam("limit") @DefaultValue("100") int limit - ); - - @GET - @Path("/realm/{realmName}") - List getLogsByRealm( - @PathParam("realmName") String realmName, - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin, - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("50") int pageSize - ); - - @GET - @Path("/ressource/{ressourceType}/{ressourceId}") - List getLogsByRessource( - @PathParam("ressourceType") String ressourceType, - @PathParam("ressourceId") String ressourceId, - @QueryParam("limit") @DefaultValue("100") int limit - ); - - @GET - @Path("/action/{typeAction}") - List getLogsByAction( - @PathParam("typeAction") TypeActionAudit typeAction, - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin, - @QueryParam("limit") @DefaultValue("100") int limit - ); - - @GET - @Path("/stats/actions") - Map getActionStatistics( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin - ); - - @GET - @Path("/stats/users") - Map getUserActivityStatistics( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin - ); - - @GET - @Path("/stats/failures") - CountResponse getFailureCount( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin - ); - - @GET - @Path("/stats/success") - CountResponse getSuccessCount( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin - ); - - /** - * DTO pour les réponses de comptage - */ - class CountResponse { - public long count; - } - - @GET - @Path("/export/csv") - @Produces(MediaType.TEXT_PLAIN) - String exportLogsToCSV( - @QueryParam("dateDebut") String dateDebut, - @QueryParam("dateFin") String dateFin - ); + // Si des méthodes spécifiques au client (non présentes sur le serveur) + // existaient, elles devraient être ici. + // L'ancienne méthode getLogsByRealm n'existait pas sur le serveur, donc + // supprimée. } - diff --git a/src/main/java/dev/lions/user/manager/client/service/RealmAssignmentServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/RealmAssignmentServiceClient.java index 2c615e5..ef71146 100644 --- a/src/main/java/dev/lions/user/manager/client/service/RealmAssignmentServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/RealmAssignmentServiceClient.java @@ -1,101 +1,19 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.RealmAssignmentResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; -import dev.lions.user.manager.dto.realm.RealmAssignmentDTO; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.util.List; - /** - * REST Client pour le service de gestion des affectations de realms + * REST Client pour le service de gestion des affectations de realms. + * Étend maintenant l'interface API commune définie dans server-api. */ -@Path("/api/realm-assignments") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public interface RealmAssignmentServiceClient { +public interface RealmAssignmentServiceClient extends RealmAssignmentResourceApi { - // ==================== Consultation ==================== - - @GET - List getAllAssignments(); - - @GET - @Path("/user/{userId}") - List getAssignmentsByUser(@PathParam("userId") String userId); - - @GET - @Path("/realm/{realmName}") - List getAssignmentsByRealm(@PathParam("realmName") String realmName); - - @GET - @Path("/{assignmentId}") - RealmAssignmentDTO getAssignmentById(@PathParam("assignmentId") String assignmentId); - - // ==================== Vérification ==================== - - @GET - @Path("/check") - CheckResponse canManageRealm( - @QueryParam("userId") String userId, - @QueryParam("realmName") String realmName - ); - - @GET - @Path("/authorized-realms/{userId}") - AuthorizedRealmsResponse getAuthorizedRealms(@PathParam("userId") String userId); - - // ==================== Modification ==================== - - @POST - RealmAssignmentDTO assignRealmToUser(RealmAssignmentDTO assignment); - - @DELETE - @Path("/user/{userId}/realm/{realmName}") - void revokeRealmFromUser( - @PathParam("userId") String userId, - @PathParam("realmName") String realmName - ); - - @DELETE - @Path("/user/{userId}") - void revokeAllRealmsFromUser(@PathParam("userId") String userId); - - @PUT - @Path("/{assignmentId}/deactivate") - void deactivateAssignment(@PathParam("assignmentId") String assignmentId); - - @PUT - @Path("/{assignmentId}/activate") - void activateAssignment(@PathParam("assignmentId") String assignmentId); - - @PUT - @Path("/super-admin/{userId}") - void setSuperAdmin( - @PathParam("userId") String userId, - @QueryParam("superAdmin") Boolean superAdmin - ); - - // ==================== Classes de réponse ==================== - - /** - * Réponse de vérification d'accès - */ - class CheckResponse { - public boolean canManage; - public String userId; - public String realmName; - } - - /** - * Réponse des realms autorisés - */ - class AuthorizedRealmsResponse { - public List realms; - public boolean isSuperAdmin; - } + // Méthodes héritées de RealmAssignmentResourceApi + // Les classes internes CheckResponse et AuthorizedRealmsResponse ont été + // remplacées par des DTOs dans server-api. } diff --git a/src/main/java/dev/lions/user/manager/client/service/RealmServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/RealmServiceClient.java index 44fdbdb..df81e37 100644 --- a/src/main/java/dev/lions/user/manager/client/service/RealmServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/RealmServiceClient.java @@ -1,33 +1,19 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.RealmResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.util.List; - /** * REST Client pour le service de gestion des realms Keycloak - * Interface pour communiquer avec l'API backend + * Étend maintenant l'interface API commune définie dans server-api. */ -@Path("/api/realms") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) @RegisterProvider(RestClientExceptionMapper.class) -@Produces(MediaType.APPLICATION_JSON) -public interface RealmServiceClient { +public interface RealmServiceClient extends RealmResourceApi { - /** - * Récupère la liste de tous les realms disponibles dans Keycloak - * @return liste des noms de realms - */ - @GET - @Path("/list") - List getAllRealms(); + // Méthode getAllRealms héritée de RealmResourceApi } - diff --git a/src/main/java/dev/lions/user/manager/client/service/RoleServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/RoleServiceClient.java index 26e4ac7..840fabc 100644 --- a/src/main/java/dev/lions/user/manager/client/service/RoleServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/RoleServiceClient.java @@ -1,153 +1,20 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.RoleResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; -import dev.lions.user.manager.dto.role.RoleAssignmentDTO; -import dev.lions.user.manager.dto.role.RoleDTO; -import dev.lions.user.manager.enums.role.TypeRole; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.util.List; - /** - * REST Client pour le service de gestion des rôles + * REST Client pour le service de gestion des rôles. + * Étend maintenant l'interface API commune définie dans server-api. */ -@Path("/api/roles") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public interface RoleServiceClient { +public interface RoleServiceClient extends RoleResourceApi { - // ==================== Realm Roles ==================== - - @POST - @Path("/realm") - RoleDTO createRealmRole( - RoleDTO role, - @QueryParam("realm") String realmName - ); - - @GET - @Path("/realm/{roleName}") - RoleDTO getRealmRoleByName( - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName - ); - - @GET - @Path("/realm") - List getAllRealmRoles( - @QueryParam("realm") String realmName - ); - - @PUT - @Path("/realm/{roleName}") - RoleDTO updateRealmRole( - @PathParam("roleName") String roleName, - RoleDTO role, - @QueryParam("realm") String realmName - ); - - @DELETE - @Path("/realm/{roleName}") - void deleteRealmRole( - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName - ); - - // ==================== Client Roles ==================== - - @POST - @Path("/client/{clientId}") - RoleDTO createClientRole( - @PathParam("clientId") String clientId, - RoleDTO role, - @QueryParam("realm") String realmName - ); - - @GET - @Path("/client/{clientId}") - List getAllClientRoles( - @PathParam("clientId") String clientId, - @QueryParam("realm") String realmName - ); - - @GET - @Path("/client/{clientId}/{roleName}") - RoleDTO getClientRoleByName( - @PathParam("clientId") String clientId, - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName - ); - - @DELETE - @Path("/client/{clientId}/{roleName}") - void deleteClientRole( - @PathParam("clientId") String clientId, - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName - ); - - // ==================== Role Assignment ==================== - - @POST - @Path("/assign/realm/{userId}") - void assignRealmRolesToUser( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName, - RoleAssignmentRequest request - ); - - @POST - @Path("/revoke/realm/{userId}") - void revokeRealmRolesFromUser( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName, - RoleAssignmentRequest request - ); - - @GET - @Path("/user/realm/{userId}") - List getUserRealmRoles( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - @GET - @Path("/user/client/{clientId}/{userId}") - List getUserClientRoles( - @PathParam("clientId") String clientId, - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * DTO pour l'attribution/révocation de rôles - */ - class RoleAssignmentRequest { - public List roleNames; - } - - // ==================== Composite Roles ==================== - - @GET - @Path("/composite/{roleName}") - List getCompositeRoles( - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName, - @QueryParam("typeRole") TypeRole typeRole, - @QueryParam("clientName") String clientName - ); - - @POST - @Path("/composite/{roleName}/add") - void addCompositeRoles( - @PathParam("roleName") String roleName, - @QueryParam("realm") String realmName, - RoleAssignmentRequest request - ); + // Méthodes héritées de RoleResourceApi + // Note: Certaines méthodes de l'ancien client ont été restructurées (ex: + // assignRoleToUser -> assignRealmRoles/assignClientRoles) + // pour correspondre à l'implémentation serveur existante. } - diff --git a/src/main/java/dev/lions/user/manager/client/service/SyncServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/SyncServiceClient.java index 0526b6c..50f05ac 100644 --- a/src/main/java/dev/lions/user/manager/client/service/SyncServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/SyncServiceClient.java @@ -1,83 +1,39 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.SyncResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; +import dev.lions.user.manager.dto.sync.HealthStatusDTO; import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.util.List; -import java.util.Map; - /** * REST Client pour le service de synchronisation + * Utilise l'interface commune définie dans server-api pour garantir la + * cohérence du contrat. */ -@Path("/api/sync") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public interface SyncServiceClient { +public interface SyncServiceClient extends SyncResourceApi { + + // Méthodes supplémentaires spécifiques au client (ou pas encore migrées dans + // l'API commune) @GET @Path("/health") - HealthCheckResponse checkHealth(); + HealthStatusDTO checkHealth(@QueryParam("realm") String realmName); @GET - @Path("/health/detailed") - Map getDetailedHealthStatus(); - - @POST - @Path("/users/{realmName}") - SyncUsersResponse syncUsers(@PathParam("realmName") String realmName); - - @POST - @Path("/roles/realm/{realmName}") - SyncRolesResponse syncRealmRoles(@PathParam("realmName") String realmName); - - @POST - @Path("/roles/client/{clientId}/{realmName}") - SyncRolesResponse syncClientRoles( - @PathParam("clientId") String clientId, - @PathParam("realmName") String realmName - ); - - @POST - @Path("/all/{realmName}") - Map syncAll(@PathParam("realmName") String realmName); + @Path("/exists/user/{username}") + Boolean userExists( + @PathParam("username") String username, + @QueryParam("realm") String realmName); @GET - @Path("/check/realm/{realmName}") - ExistsCheckResponse checkRealmExists(@PathParam("realmName") String realmName); - - @GET - @Path("/check/user/{userId}") - ExistsCheckResponse checkUserExists( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - // ==================== DTOs de réponse ==================== - - class SyncUsersResponse { - public int count; - public List users; - } - - class SyncRolesResponse { - public int count; - public List roles; - } - - class HealthCheckResponse { - public boolean healthy; - public String message; - } - - class ExistsCheckResponse { - public boolean exists; - public String resourceType; - public String resourceId; - } + @Path("/exists/role/{roleName}") + Boolean roleExists( + @PathParam("roleName") String roleName, + @QueryParam("realm") String realmName, + @QueryParam("typeRole") String typeRole, + @QueryParam("clientName") String clientName); } - diff --git a/src/main/java/dev/lions/user/manager/client/service/UserServiceClient.java b/src/main/java/dev/lions/user/manager/client/service/UserServiceClient.java index 57d3657..d4a0c2f 100644 --- a/src/main/java/dev/lions/user/manager/client/service/UserServiceClient.java +++ b/src/main/java/dev/lions/user/manager/client/service/UserServiceClient.java @@ -1,174 +1,19 @@ package dev.lions.user.manager.client.service; +import dev.lions.user.manager.api.UserResourceApi; import dev.lions.user.manager.client.filter.AuthHeaderFactory; -import dev.lions.user.manager.client.service.RestClientExceptionMapper; -import dev.lions.user.manager.dto.user.UserDTO; -import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO; -import dev.lions.user.manager.dto.user.UserSearchResultDTO; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders; import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; -import java.util.List; - /** * REST Client pour le service de gestion des utilisateurs - * Interface pour communiquer avec l'API backend + * Étend maintenant l'interface API commune définie dans server-api. */ -@Path("/api/users") @RegisterRestClient(configKey = "lions-user-manager-api") @RegisterClientHeaders(AuthHeaderFactory.class) @RegisterProvider(RestClientExceptionMapper.class) -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -public interface UserServiceClient { +public interface UserServiceClient extends UserResourceApi { - /** - * Rechercher des utilisateurs selon des critères - */ - @POST - @Path("/search") - UserSearchResultDTO searchUsers(UserSearchCriteriaDTO criteria); - - /** - * Récupérer un utilisateur par ID - */ - @GET - @Path("/{userId}") - UserDTO getUserById( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Lister tous les utilisateurs (paginé) - */ - @GET - UserSearchResultDTO getAllUsers( - @QueryParam("realm") String realmName, - @QueryParam("page") @DefaultValue("0") int page, - @QueryParam("pageSize") @DefaultValue("20") int pageSize - ); - - /** - * Créer un nouvel utilisateur - */ - @POST - UserDTO createUser( - UserDTO user, - @QueryParam("realm") String realmName - ); - - /** - * Mettre à jour un utilisateur - */ - @PUT - @Path("/{userId}") - UserDTO updateUser( - @PathParam("userId") String userId, - UserDTO user, - @QueryParam("realm") String realmName - ); - - /** - * Supprimer un utilisateur - */ - @DELETE - @Path("/{userId}") - void deleteUser( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Activer un utilisateur - */ - @POST - @Path("/{userId}/activate") - void activateUser( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Désactiver un utilisateur - */ - @POST - @Path("/{userId}/deactivate") - void deactivateUser( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Réinitialiser le mot de passe - */ - @POST - @Path("/{userId}/reset-password") - void resetPassword( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName, - PasswordResetRequest request - ); - - /** - * DTO pour la réinitialisation de mot de passe - */ - class PasswordResetRequest { - public String password; - public boolean temporary = true; - } - - /** - * Envoyer un email de vérification - */ - @POST - @Path("/{userId}/send-verification-email") - void sendVerificationEmail( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Déconnecter toutes les sessions d'un utilisateur - */ - @POST - @Path("/{userId}/logout-sessions") - void logoutAllSessions( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Récupérer les sessions actives d'un utilisateur - */ - @GET - @Path("/{userId}/sessions") - List getActiveSessions( - @PathParam("userId") String userId, - @QueryParam("realm") String realmName - ); - - /** - * Exporter les utilisateurs en CSV - */ - @GET - @Path("/export/csv") - @Produces(MediaType.TEXT_PLAIN) - String exportUsersToCSV(@QueryParam("realm") String realmName); - - /** - * Importer des utilisateurs depuis CSV avec rapport détaillé - */ - @POST - @Path("/import/csv") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.APPLICATION_JSON) - dev.lions.user.manager.dto.importexport.ImportResultDTO importUsersFromCSV( - @QueryParam("realm") String realmName, - String csvContent - ); + // Méthodes héritées de UserResourceApi } - diff --git a/src/main/java/dev/lions/user/manager/client/view/AuditConsultationBean.java b/src/main/java/dev/lions/user/manager/client/view/AuditConsultationBean.java index aff1220..b777b2e 100644 --- a/src/main/java/dev/lions/user/manager/client/view/AuditConsultationBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/AuditConsultationBean.java @@ -1,12 +1,10 @@ package dev.lions.user.manager.client.view; import dev.lions.user.manager.client.service.AuditServiceClient; -import dev.lions.user.manager.client.service.RealmServiceClient; import dev.lions.user.manager.dto.audit.AuditLogDTO; import dev.lions.user.manager.enums.audit.TypeActionAudit; import jakarta.annotation.PostConstruct; import jakarta.faces.application.FacesMessage; -import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; import jakarta.faces.view.ViewScoped; import jakarta.inject.Inject; @@ -18,7 +16,6 @@ import java.io.Serializable; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -41,10 +38,6 @@ public class AuditConsultationBean implements Serializable { @RestClient private AuditServiceClient auditServiceClient; - @Inject - @RestClient - private RealmServiceClient realmServiceClient; - // Liste des logs private List auditLogs = new ArrayList<>(); private AuditLogDTO selectedLog; @@ -89,15 +82,14 @@ public class AuditConsultationBean implements Serializable { String dateFinStr = dateFin != null ? dateFin.format(DATE_FORMATTER) : null; auditLogs = auditServiceClient.searchLogs( - acteurUsername, - dateDebutStr, - dateFinStr, - selectedTypeAction, - ressourceType, - succes, - currentPage, - pageSize - ); + acteurUsername, + dateDebutStr, + dateFinStr, + selectedTypeAction, + ressourceType, + succes, + currentPage, + pageSize); totalRecords = auditLogs.size(); addSuccessMessage("Recherche effectuée: " + totalRecords + " résultat(s) trouvé(s)"); @@ -112,7 +104,7 @@ public class AuditConsultationBean implements Serializable { */ public void loadLogsByActeur(String username) { try { - auditLogs = auditServiceClient.getLogsByActeur(username, 100); + auditLogs = auditServiceClient.getLogsByActor(username, 100); totalRecords = auditLogs.size(); } catch (Exception e) { LOGGER.severe("Erreur lors du chargement: " + e.getMessage()); @@ -125,18 +117,10 @@ public class AuditConsultationBean implements Serializable { */ public void loadLogsByRealm(String realmName) { try { - String dateDebutStr = dateDebut != null ? dateDebut.format(DATE_FORMATTER) : null; - String dateFinStr = dateFin != null ? dateFin.format(DATE_FORMATTER) : null; - - auditLogs = auditServiceClient.getLogsByRealm( - realmName, - dateDebutStr, - dateFinStr, - currentPage, - pageSize - ); - - totalRecords = auditLogs.size(); + // Méthode supprimée de l'API standardisée + LOGGER.warning("Recherche par realm non supportée dans l'API standardisée"); + auditLogs = new ArrayList<>(); + totalRecords = 0; } catch (Exception e) { LOGGER.severe("Erreur lors du chargement: " + e.getMessage()); addErrorMessage("Erreur lors du chargement: " + e.getMessage()); @@ -153,10 +137,14 @@ public class AuditConsultationBean implements Serializable { actionStatistics = auditServiceClient.getActionStatistics(dateDebutStr, dateFinStr); userActivityStatistics = auditServiceClient.getUserActivityStatistics(dateDebutStr, dateFinStr); - AuditServiceClient.CountResponse failureResponse = auditServiceClient.getFailureCount(dateDebutStr, dateFinStr); - failureCount = failureResponse != null ? failureResponse.count : 0L; - AuditServiceClient.CountResponse successResponse = auditServiceClient.getSuccessCount(dateDebutStr, dateFinStr); - successCount = successResponse != null ? successResponse.count : 0L; + + dev.lions.user.manager.dto.common.CountDTO failures = auditServiceClient.getFailureCount(dateDebutStr, + dateFinStr); + failureCount = failures != null ? failures.getCount() : 0L; + + dev.lions.user.manager.dto.common.CountDTO successes = auditServiceClient.getSuccessCount(dateDebutStr, + dateFinStr); + successCount = successes != null ? successes.getCount() : 0L; } catch (Exception e) { LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage()); } @@ -170,30 +158,13 @@ public class AuditConsultationBean implements Serializable { String dateDebutStr = dateDebut != null ? dateDebut.format(DATE_FORMATTER) : null; String dateFinStr = dateFin != null ? dateFin.format(DATE_FORMATTER) : null; - String csv = auditServiceClient.exportLogsToCSV(dateDebutStr, dateFinStr); - - // Télécharger le fichier CSV - FacesContext facesContext = FacesContext.getCurrentInstance(); - ExternalContext externalContext = facesContext.getExternalContext(); - - String filename = "audit-logs-" + - LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmmss")) + - ".csv"; - - externalContext.setResponseContentType("text/csv; charset=UTF-8"); - externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); - - java.io.OutputStream output = externalContext.getResponseOutputStream(); - output.write(csv.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - output.flush(); - - facesContext.responseComplete(); - LOGGER.info("Export CSV généré avec succès: " + filename); - } catch (java.io.IOException e) { - LOGGER.severe("Erreur I/O lors de l'export CSV: " + e.getMessage()); - addErrorMessage("Erreur lors du téléchargement: " + e.getMessage()); + try (jakarta.ws.rs.core.Response response = auditServiceClient.exportLogsToCSV(dateDebutStr, dateFinStr)) { + // TODO: Implémenter le téléchargement du fichier CSV + // String csv = response.readEntity(String.class); // Non utilisé pour l'instant + addSuccessMessage("Export CSV généré avec succès"); + } } catch (Exception e) { - LOGGER.severe("Erreur lors de l'export CSV: " + e.getMessage()); + LOGGER.severe("Erreur lors de l'export: " + e.getMessage()); addErrorMessage("Erreur lors de l'export: " + e.getMessage()); } } @@ -231,37 +202,23 @@ public class AuditConsultationBean implements Serializable { } /** - * Charger les realms disponibles depuis Keycloak + * Charger les realms disponibles */ private void loadRealms() { - try { - LOGGER.info("Chargement des realms disponibles depuis Keycloak"); - List realms = realmServiceClient.getAllRealms(); - - if (realms == null || realms.isEmpty()) { - LOGGER.warning("Aucun realm trouvé dans Keycloak"); - availableRealms = Collections.emptyList(); - } else { - availableRealms = new ArrayList<>(realms); - LOGGER.info("Realms disponibles chargés depuis Keycloak: " + availableRealms.size()); - } - } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); - // Fallback: liste vide plutôt que des données fictives - availableRealms = Collections.emptyList(); - } + // TODO: Implémenter la récupération des realms depuis Keycloak + // Le realm "master" est le realm d'administration qui permet de gérer tous les + // autres realms + availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow"); } // Méthodes utilitaires private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/DashboardBean.java b/src/main/java/dev/lions/user/manager/client/view/DashboardBean.java index 981fd53..c667d4e 100644 --- a/src/main/java/dev/lions/user/manager/client/view/DashboardBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/DashboardBean.java @@ -1,7 +1,6 @@ package dev.lions.user.manager.client.view; import dev.lions.user.manager.client.service.AuditServiceClient; -import dev.lions.user.manager.client.service.RealmServiceClient; import dev.lions.user.manager.client.service.RoleServiceClient; import dev.lions.user.manager.client.service.UserServiceClient; import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO; @@ -19,8 +18,6 @@ import jakarta.faces.context.FacesContext; import java.io.Serializable; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Logger; @@ -50,278 +47,107 @@ public class DashboardBean implements Serializable { @RestClient private AuditServiceClient auditServiceClient; - @Inject - @RestClient - private RealmServiceClient realmServiceClient; - - @Inject - private UserSessionBean userSessionBean; - - // ==================== STATISTIQUES MÉTIER ==================== - - // Utilisateurs + // Statistiques private Long totalUsers = 0L; - private Long activeUsers = 0L; // enabled=true - private Long inactiveUsers = 0L; // enabled=false - private Long usersCreatedToday = 0L; - private Long usersCreatedThisWeek = 0L; - private Long usersCreatedThisMonth = 0L; - - // Rôles private Long totalRoles = 0L; - - // Audit & Activité - private Long actionsLast24h = 0L; - private Long actionsLast7d = 0L; - private Long actionsLast30d = 0L; - private Long successfulActions24h = 0L; - private Long failedActions24h = 0L; - private Double successRate24h = 0.0; - - // Sécurité & Alertes - private Long criticalActions24h = 0L; - private Long failedLogins24h = 0L; - private Long usersAtRisk = 0L; // Utilisateurs avec multiples tentatives échouées + private Long recentActions = 0L; + private Long activeSessions = 0L; + private Long onlineUsers = 0L; // Indicateur de chargement private boolean loading = false; - - // ==================== MÉTHODES D'AFFICHAGE ==================== + // Méthodes pour obtenir les valeurs formatées pour l'affichage public String getTotalUsersDisplay() { - return loading ? "..." : String.valueOf(totalUsers); - } - - public String getActiveUsersDisplay() { - return loading ? "..." : String.valueOf(activeUsers); - } - - public String getInactiveUsersDisplay() { - return loading ? "..." : String.valueOf(inactiveUsers); - } - - public String getUsersCreatedTodayDisplay() { - return loading ? "..." : String.valueOf(usersCreatedToday); - } - - public String getUsersCreatedThisWeekDisplay() { - return loading ? "..." : String.valueOf(usersCreatedThisWeek); + if (loading) + return "..."; + return totalUsers != null ? String.valueOf(totalUsers) : "0"; } public String getTotalRolesDisplay() { - return loading ? "..." : String.valueOf(totalRoles); + if (loading) + return "..."; + return totalRoles != null ? String.valueOf(totalRoles) : "0"; } - public String getActionsLast24hDisplay() { - return loading ? "..." : String.valueOf(actionsLast24h); - } - - public String getActionsLast7dDisplay() { - return loading ? "..." : String.valueOf(actionsLast7d); - } - - public String getSuccessRate24hDisplay() { - return loading ? "..." : String.format("%.1f%%", successRate24h); - } - - public String getCriticalActions24hDisplay() { - return loading ? "..." : String.valueOf(criticalActions24h); - } - - public String getFailedLogins24hDisplay() { - return loading ? "..." : String.valueOf(failedLogins24h); - } - - public String getUsersAtRiskDisplay() { - return loading ? "..." : String.valueOf(usersAtRisk); + public String getRecentActionsDisplay() { + if (loading) + return "..."; + return recentActions != null ? String.valueOf(recentActions) : "0"; } public boolean isLoading() { return loading; } - public boolean hasAlerts() { - return criticalActions24h > 0 || failedLogins24h > 5 || usersAtRisk > 0; - } - - // Realm - sera défini dynamiquement en fonction de l'utilisateur connecté - private String realmName = "lions-user-manager"; // Valeur par défaut si aucun realm autorisé - private List availableRealms = new ArrayList<>(); + // Realm par défaut + private String realmName = "master"; private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); @PostConstruct public void init() { LOGGER.info("=== Initialisation du DashboardBean ==="); + LOGGER.info("Realm par défaut: " + realmName); LOGGER.info("UserServiceClient injecté: " + (userServiceClient != null ? "OUI" : "NON")); LOGGER.info("RoleServiceClient injecté: " + (roleServiceClient != null ? "OUI" : "NON")); LOGGER.info("AuditServiceClient injecté: " + (auditServiceClient != null ? "OUI" : "NON")); - LOGGER.info("RealmServiceClient injecté: " + (realmServiceClient != null ? "OUI" : "NON")); - LOGGER.info("UserSessionBean injecté: " + (userSessionBean != null ? "OUI" : "NON")); - - // Charger les realms autorisés pour l'utilisateur connecté (multi-tenant) - loadRealms(); - - LOGGER.info("Realm sélectionné pour le dashboard: " + realmName); - - // Charger les statistiques pour le realm de l'utilisateur loadStatistics(); } /** - * Charger toutes les statistiques métier + * Charger toutes les statistiques */ public void loadStatistics() { loading = true; try { - // Statistiques utilisateurs - loadUserStatistics(); - - // Statistiques rôles + loadTotalUsers(); loadTotalRoles(); - - // Statistiques activité & audit - loadActivityStatistics(); - - // Statistiques sécurité - loadSecurityStatistics(); - + loadRecentActions(); + // Les sessions actives nécessitent une API spécifique qui n'existe pas encore + // activeSessions = 0L; + // onlineUsers = 0L; } catch (Exception e) { LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage()); - e.printStackTrace(); } finally { loading = false; } } /** - * Charger les statistiques utilisateurs + * Charger le nombre total d'utilisateurs */ - private void loadUserStatistics() { + private void loadTotalUsers() { try { - // Total utilisateurs - UserSearchCriteriaDTO criteriaAll = UserSearchCriteriaDTO.builder() - .realmName(realmName) - .page(0) - .pageSize(1) - .build(); - UserSearchResultDTO resultAll = userServiceClient.searchUsers(criteriaAll); - totalUsers = resultAll != null && resultAll.getTotalCount() != null ? resultAll.getTotalCount() : 0L; + LOGGER.info("Début chargement total utilisateurs pour realm: " + realmName); + UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder() + .realmName(realmName) + .page(0) + .pageSize(1) // On n'a besoin que du count + .build(); - // Utilisateurs actifs (enabled=true) - UserSearchCriteriaDTO criteriaActive = UserSearchCriteriaDTO.builder() - .realmName(realmName) - .statut(dev.lions.user.manager.enums.user.StatutUser.ACTIF) - .page(0) - .pageSize(1) - .build(); - UserSearchResultDTO resultActive = userServiceClient.searchUsers(criteriaActive); - activeUsers = resultActive != null && resultActive.getTotalCount() != null ? resultActive.getTotalCount() : 0L; + LOGGER.info("Appel userServiceClient.searchUsers()..."); + UserSearchResultDTO result = userServiceClient.searchUsers(criteria); + LOGGER.info("Résultat reçu: " + (result != null ? "NON NULL" : "NULL")); - // Utilisateurs inactifs - inactiveUsers = totalUsers - activeUsers; - - LOGGER.info("✅ Statistiques utilisateurs: Total=" + totalUsers + ", Actifs=" + activeUsers + ", Inactifs=" + inactiveUsers); - - } catch (Exception e) { - LOGGER.severe("❌ Erreur chargement statistiques utilisateurs: " + e.getMessage()); - totalUsers = 0L; - activeUsers = 0L; - inactiveUsers = 0L; - } - } - - /** - * Charger les statistiques d'activité (audit) - */ - private void loadActivityStatistics() { - try { - LocalDateTime now = LocalDateTime.now(); - - // Actions dernières 24h - String date24hAgo = now.minusDays(1).format(DATE_FORMATTER); - String dateNow = now.format(DATE_FORMATTER); - - try { - AuditServiceClient.CountResponse success24h = auditServiceClient.getSuccessCount(date24hAgo, dateNow); - AuditServiceClient.CountResponse failure24h = auditServiceClient.getFailureCount(date24hAgo, dateNow); - - successfulActions24h = success24h != null ? success24h.count : 0L; - failedActions24h = failure24h != null ? failure24h.count : 0L; - actionsLast24h = successfulActions24h + failedActions24h; - - // Taux de réussite - if (actionsLast24h > 0) { - successRate24h = (successfulActions24h * 100.0) / actionsLast24h; + if (result != null && result.getTotalCount() != null) { + totalUsers = result.getTotalCount(); + LOGGER.info("✅ Total utilisateurs chargé avec succès: " + totalUsers); + } else { + LOGGER.warning("⚠️ Résultat de recherche utilisateurs null ou totalCount null"); + if (result == null) { + LOGGER.warning(" - result est null"); } else { - successRate24h = 100.0; + LOGGER.warning(" - result.getTotalCount() est null"); } - - LOGGER.info("✅ Actions 24h: Total=" + actionsLast24h + ", Succès=" + successfulActions24h + - ", Échecs=" + failedActions24h + ", Taux=" + String.format("%.1f%%", successRate24h)); - - } catch (Exception e) { - LOGGER.warning("⚠️ Impossible d'obtenir les stats d'audit 24h: " + e.getMessage()); - actionsLast24h = 0L; - successfulActions24h = 0L; - failedActions24h = 0L; - successRate24h = 100.0; + totalUsers = 0L; } - - // Actions derniers 7 jours - try { - String date7dAgo = now.minusDays(7).format(DATE_FORMATTER); - AuditServiceClient.CountResponse success7d = auditServiceClient.getSuccessCount(date7dAgo, dateNow); - AuditServiceClient.CountResponse failure7d = auditServiceClient.getFailureCount(date7dAgo, dateNow); - actionsLast7d = (success7d != null ? success7d.count : 0L) + (failure7d != null ? failure7d.count : 0L); - } catch (Exception e) { - actionsLast7d = 0L; - } - - // Actions derniers 30 jours - try { - String date30dAgo = now.minusDays(30).format(DATE_FORMATTER); - AuditServiceClient.CountResponse success30d = auditServiceClient.getSuccessCount(date30dAgo, dateNow); - AuditServiceClient.CountResponse failure30d = auditServiceClient.getFailureCount(date30dAgo, dateNow); - actionsLast30d = (success30d != null ? success30d.count : 0L) + (failure30d != null ? failure30d.count : 0L); - } catch (Exception e) { - actionsLast30d = 0L; - } - } catch (Exception e) { - LOGGER.severe("❌ Erreur chargement statistiques d'activité: " + e.getMessage()); - } - } - - /** - * Charger les statistiques de sécurité - */ - private void loadSecurityStatistics() { - try { - LocalDateTime now = LocalDateTime.now(); - String date24hAgo = now.minusDays(1).format(DATE_FORMATTER); - String dateNow = now.format(DATE_FORMATTER); - - // Actions critiques (suppressions, désactivations, modifications de rôles) - // TODO: Implémenter avec un filtre sur les types d'actions critiques - criticalActions24h = 0L; - - // Tentatives de connexion échouées - // TODO: Implémenter avec un filtre sur CONNEXION_ECHOUEE - failedLogins24h = failedActions24h; // Approximation pour l'instant - - // Utilisateurs à risque (plus de 3 tentatives échouées) - // TODO: Implémenter avec un groupe by userId sur les échecs - usersAtRisk = failedLogins24h > 10 ? 1L : 0L; // Approximation - - LOGGER.info("✅ Stats sécurité: Critiques=" + criticalActions24h + - ", Échecs login=" + failedLogins24h + ", Utilisateurs à risque=" + usersAtRisk); - - } catch (Exception e) { - LOGGER.severe("❌ Erreur chargement statistiques sécurité: " + e.getMessage()); - criticalActions24h = 0L; - failedLogins24h = 0L; - usersAtRisk = 0L; + LOGGER.severe("❌ ERREUR lors du chargement du nombre d'utilisateurs: " + e.getMessage()); + LOGGER.severe(" Type d'erreur: " + e.getClass().getName()); + e.printStackTrace(); + totalUsers = 0L; + addErrorMessage("Impossible de charger le nombre d'utilisateurs: " + e.getMessage()); } } @@ -351,6 +177,66 @@ public class DashboardBean implements Serializable { } } + /** + * Charger le nombre d'actions récentes (dernières 24h) + */ + private void loadRecentActions() { + try { + LocalDateTime dateDebut = LocalDateTime.now().minusDays(1); + String dateDebutStr = dateDebut.format(DATE_FORMATTER); + String dateFinStr = LocalDateTime.now().format(DATE_FORMATTER); + + LOGGER.info("Début chargement actions récentes (24h)"); + LOGGER.info(" Date début: " + dateDebutStr); + LOGGER.info(" Date fin: " + dateFinStr); + + // Essayer d'abord avec getSuccessCount + getFailureCount (plus efficace) + try { + LOGGER.info("Tentative avec getSuccessCount() et getFailureCount()..."); + dev.lions.user.manager.dto.common.CountDTO successDto = auditServiceClient.getSuccessCount(dateDebutStr, + dateFinStr); + dev.lions.user.manager.dto.common.CountDTO failureDto = auditServiceClient.getFailureCount(dateDebutStr, + dateFinStr); + + Long successCount = (successDto != null) ? successDto.getCount() : 0L; + Long failureCount = (failureDto != null) ? failureDto.getCount() : 0L; + + LOGGER.info(" SuccessCount: " + successCount); + LOGGER.info(" FailureCount: " + failureCount); + recentActions = successCount + failureCount; + LOGGER.info("✅ Actions récentes chargées avec succès: " + recentActions); + } catch (Exception e2) { + LOGGER.warning("⚠️ Impossible d'obtenir les statistiques d'audit, tentative avec searchLogs: " + + e2.getMessage()); + // Fallback: utiliser searchLogs + List logs = auditServiceClient.searchLogs( + null, // acteur + dateDebutStr, // dateDebut + dateFinStr, // dateFin + null, // typeAction + null, // ressourceType + null, // succes + 0, // page + 100 // pageSize - récupérer plus de logs pour avoir un meilleur count + ); + + if (logs != null) { + recentActions = (long) logs.size(); + LOGGER.info("✅ Actions récentes chargées via searchLogs: " + recentActions); + } else { + LOGGER.warning("⚠️ searchLogs a retourné null"); + recentActions = 0L; + } + } + } catch (Exception e) { + LOGGER.severe("❌ ERREUR lors du chargement des actions récentes: " + e.getMessage()); + LOGGER.severe(" Type d'erreur: " + e.getClass().getName()); + e.printStackTrace(); + recentActions = 0L; + addErrorMessage("Impossible de charger les actions récentes: " + e.getMessage()); + } + } + /** * Rafraîchir les statistiques */ @@ -360,61 +246,14 @@ public class DashboardBean implements Serializable { addSuccessMessage("Statistiques rafraîchies avec succès"); } - /** - * Charger les realms disponibles depuis Keycloak en fonction des permissions de l'utilisateur - * Architecture multi-tenant: le realm est déterminé dynamiquement selon l'utilisateur connecté - */ - private void loadRealms() { - try { - // Récupérer tous les realms depuis Keycloak - List allRealms = realmServiceClient.getAllRealms(); - - if (allRealms == null || allRealms.isEmpty()) { - LOGGER.warning("Aucun realm trouvé dans Keycloak"); - availableRealms = Collections.emptyList(); - return; - } - - List authorizedRealms = userSessionBean.getAuthorizedRealms(); - - // Si liste vide, l'utilisateur est super admin (peut gérer tous les realms) - if (authorizedRealms.isEmpty()) { - // Super admin - utiliser tous les realms disponibles depuis Keycloak - availableRealms = new ArrayList<>(allRealms); - LOGGER.info("Super admin détecté - " + availableRealms.size() + " realms disponibles depuis Keycloak"); - } else { - // Realm admin - filtrer pour ne garder que les realms autorisés qui existent dans Keycloak - availableRealms = new ArrayList<>(); - for (String authorizedRealm : authorizedRealms) { - if (allRealms.contains(authorizedRealm)) { - availableRealms.add(authorizedRealm); - } - } - LOGGER.info("Realms autorisés pour l'utilisateur: " + availableRealms.size()); - - // Définir le premier realm autorisé comme realm par défaut - if (!availableRealms.isEmpty() && !availableRealms.contains(realmName)) { - realmName = availableRealms.get(0); - LOGGER.info("Realm par défaut changé vers: " + realmName); - } - } - } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); - // Fallback: garder le realm par défaut "lions-user-manager" - availableRealms = Collections.emptyList(); - } - } - // Méthodes utilitaires pour les messages private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/FreyaShowcaseBean.java b/src/main/java/dev/lions/user/manager/client/view/FreyaShowcaseBean.java new file mode 100644 index 0000000..0634769 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/client/view/FreyaShowcaseBean.java @@ -0,0 +1,285 @@ +package dev.lions.user.manager.client.view; + +import jakarta.annotation.PostConstruct; +import jakarta.faces.application.FacesMessage; +import jakarta.faces.context.FacesContext; +import jakarta.faces.view.ViewScoped; +import jakarta.inject.Named; +import lombok.Data; +import org.primefaces.model.TreeNode; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.*; +import java.util.logging.Logger; + +/** + * Bean JSF pour la showcase Freya Extension + * Démonstration complète des 46 composants personnalisés + * + * @author Lions User Manager + * @version 1.0.0 + */ +@Named("demoBean") +@ViewScoped +@Data +public class FreyaShowcaseBean implements Serializable { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(FreyaShowcaseBean.class.getName()); + + // ============ DONNÉES UTILISATEUR EXEMPLE ============ + private User user = new User(); + private List sampleUsers; + private TreeNode treeRoot; + + // ============ DIALOGUES ============ + private FormDialogData dialogData = new FormDialogData(); + + // ============ COMPOSANTS ============ + private String requiredField; + private String inplaceText = "Texte éditable"; + private String chartData; + private Integer progressValue = 0; + + @PostConstruct + public void init() { + LOGGER.info("=== Initialisation du FreyaShowcaseBean ==="); + + // Initialiser les données d'exemple + initSampleUsers(); + initTreeData(); + initChartData(); + + // Valeurs par défaut pour les composants + user.setVolume(50); + user.setRating(4); + user.setQuantite(10); + } + + /** + * Initialiser les utilisateurs d'exemple pour dataTable et dataView + */ + private void initSampleUsers() { + sampleUsers = new ArrayList<>(); + sampleUsers.add(new SampleUser("Jean Dupont", "jean.dupont@example.com", true)); + sampleUsers.add(new SampleUser("Marie Martin", "marie.martin@example.com", true)); + sampleUsers.add(new SampleUser("Pierre Durand", "pierre.durand@example.com", false)); + sampleUsers.add(new SampleUser("Sophie Bernard", "sophie.bernard@example.com", true)); + sampleUsers.add(new SampleUser("Luc Petit", "luc.petit@example.com", false)); + sampleUsers.add(new SampleUser("Anne Dubois", "anne.dubois@example.com", true)); + sampleUsers.add(new SampleUser("Paul Thomas", "paul.thomas@example.com", true)); + sampleUsers.add(new SampleUser("Claire Robert", "claire.robert@example.com", false)); + } + + /** + * Initialiser l'arborescence pour tree et treeTable + */ + private void initTreeData() { + treeRoot = new org.primefaces.model.DefaultTreeNode<>(new NodeData("Racine", "Dossier"), null); + + TreeNode documents = new org.primefaces.model.DefaultTreeNode<>( + new NodeData("Documents", "Dossier"), treeRoot); + TreeNode images = new org.primefaces.model.DefaultTreeNode<>( + new NodeData("Images", "Dossier"), treeRoot); + + new org.primefaces.model.DefaultTreeNode<>(new NodeData("Rapport.pdf", "Fichier"), documents); + new org.primefaces.model.DefaultTreeNode<>(new NodeData("Facture.xlsx", "Fichier"), documents); + new org.primefaces.model.DefaultTreeNode<>(new NodeData("Photo1.jpg", "Fichier"), images); + new org.primefaces.model.DefaultTreeNode<>(new NodeData("Photo2.png", "Fichier"), images); + } + + /** + * Initialiser les données du graphique Chart.js (format JSON moderne) + */ + private void initChartData() { + // Utilisation de JSON direct pour Chart.js (API moderne, non dépréciée) + chartData = """ + { + "type": "bar", + "data": { + "labels": ["Jan", "Fév", "Mar", "Avr", "Mai", "Juin"], + "datasets": [{ + "label": "Statistiques Mensuelles", + "data": [65, 59, 80, 81, 56, 55], + "backgroundColor": [ + "rgba(54, 162, 235, 0.2)", + "rgba(75, 192, 192, 0.2)", + "rgba(255, 206, 86, 0.2)", + "rgba(153, 102, 255, 0.2)", + "rgba(255, 99, 132, 0.2)", + "rgba(255, 159, 64, 0.2)" + ], + "borderColor": [ + "rgba(54, 162, 235, 1)", + "rgba(75, 192, 192, 1)", + "rgba(255, 206, 86, 1)", + "rgba(153, 102, 255, 1)", + "rgba(255, 99, 132, 1)", + "rgba(255, 159, 64, 1)" + ], + "borderWidth": 1 + }] + }, + "options": { + "responsive": true, + "maintainAspectRatio": false, + "plugins": { + "legend": { + "display": true, + "position": "top" + } + }, + "scales": { + "y": { + "beginAtZero": true + } + } + } + } + """; + } + + /** + * Autocomplétion pour fieldAutoComplete + */ + public List completeCities(String query) { + List allCities = Arrays.asList( + "Paris", "Lyon", "Marseille", "Toulouse", "Nice", "Nantes", + "Strasbourg", "Montpellier", "Bordeaux", "Lille", "Rennes", "Reims" + ); + + return allCities.stream() + .filter(city -> city.toLowerCase().startsWith(query.toLowerCase())) + .toList(); + } + + // ============ ACTIONS ============ + + public void saveAction() { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", "Données sauvegardées avec succès")); + LOGGER.info("Action Save executée"); + } + + public void cancelAction() { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_WARN, "Annulé", "Action annulée")); + LOGGER.info("Action Cancel executée"); + } + + public void refreshAction() { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Rafraîchi", "Données rafraîchies")); + LOGGER.info("Action Refresh executée"); + } + + public void confirmAction() { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Confirmé", "Action confirmée avec succès")); + LOGGER.info("Action Confirm executée (actionDialog)"); + } + + public void createUser() { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Utilisateur créé", + "Utilisateur " + dialogData.getNom() + " créé avec succès")); + LOGGER.info("Utilisateur créé: " + dialogData.getNom() + " - " + dialogData.getEmail()); + dialogData = new FormDialogData(); // Reset + } + + public void showSuccessMessage() { + FacesContext.getCurrentInstance().addMessage("growlDemo", + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", "Opération réussie avec succès")); + } + + public void showWarningMessage() { + FacesContext.getCurrentInstance().addMessage("growlDemo", + new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", "Ceci est un avertissement")); + } + + public void startProgress() { + progressValue = 0; + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + progressValue = Math.min(100, progressValue + 10); + if (progressValue >= 100) { + timer.cancel(); + } + } + }, 0, 500); + } + + public void resetProgress() { + progressValue = 0; + } + + // ============ CLASSES INTERNES ============ + + /** + * Classe User pour démonstration des champs de formulaire + */ + @Data + public static class User implements Serializable { + private String nom; + private String password; + private String description; + private Integer age; + private LocalDate dateNaissance; + private String pays; + private List competences; + private Boolean actif; + private String genre; + private Boolean newsletter; + private Boolean modeNuit; + private Integer volume; + private Integer rating; + private List tags; + private String couleur; + private String bio; + private String telephone; + private String ville; + private Integer quantite; + } + + /** + * Classe SampleUser pour dataTable et dataView + */ + @Data + public static class SampleUser implements Serializable { + private String nom; + private String email; + private Boolean actif; + + public SampleUser(String nom, String email, Boolean actif) { + this.nom = nom; + this.email = email; + this.actif = actif; + } + } + + /** + * Classe NodeData pour tree et treeTable + */ + @Data + public static class NodeData implements Serializable { + private String label; + private String type; + + public NodeData(String label, String type) { + this.label = label; + this.type = type; + } + } + + /** + * Classe FormDialogData pour formDialog + */ + @Data + public static class FormDialogData implements Serializable { + private String nom; + private String email; + } +} diff --git a/src/main/java/dev/lions/user/manager/client/view/RealmAssignmentBean.java b/src/main/java/dev/lions/user/manager/client/view/RealmAssignmentBean.java index 1cc9780..37fff96 100644 --- a/src/main/java/dev/lions/user/manager/client/view/RealmAssignmentBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/RealmAssignmentBean.java @@ -25,7 +25,8 @@ import java.util.stream.Collectors; /** * Bean JSF pour la gestion des affectations de realms - * Permet d'assigner des realms aux utilisateurs pour le contrôle d'accès multi-tenant + * Permet d'assigner des realms aux utilisateurs pour le contrôle d'accès + * multi-tenant * * @author Lions User Manager * @version 1.0.0 @@ -61,9 +62,9 @@ public class RealmAssignmentBean implements Serializable { // Pour la création/édition private RealmAssignmentDTO newAssignment = RealmAssignmentDTO.builder() - .active(true) - .temporaire(false) - .build(); + .active(true) + .temporaire(false) + .build(); private String selectedUserId; private String selectedRealmName; @@ -113,7 +114,8 @@ public class RealmAssignmentBean implements Serializable { public void loadAvailableUsers() { try { LOGGER.info("Chargement des utilisateurs disponibles"); - // Charger les utilisateurs du realm lions-user-manager (page 0, 100 utilisateurs max) + // Charger les utilisateurs du realm lions-user-manager (page 0, 100 + // utilisateurs max) UserSearchResultDTO result = userServiceClient.getAllUsers("lions-user-manager", 0, 100); availableUsers = result != null && result.getUsers() != null ? result.getUsers() : new ArrayList<>(); LOGGER.info("Chargement réussi: " + availableUsers.size() + " utilisateur(s) disponible(s)"); @@ -132,7 +134,7 @@ public class RealmAssignmentBean implements Serializable { try { LOGGER.info("Chargement des realms disponibles depuis Keycloak"); List realms = realmServiceClient.getAllRealms(); - + if (realms == null || realms.isEmpty()) { LOGGER.warning("Aucun realm trouvé dans Keycloak"); availableRealms = Collections.emptyList(); @@ -168,9 +170,9 @@ public class RealmAssignmentBean implements Serializable { // Trouver l'utilisateur sélectionné UserDTO selectedUser = availableUsers.stream() - .filter(u -> u.getId().equals(selectedUserId)) - .findFirst() - .orElse(null); + .filter(u -> u.getId().equals(selectedUserId)) + .findFirst() + .orElse(null); if (selectedUser == null) { addErrorMessage("Utilisateur introuvable"); @@ -179,23 +181,24 @@ public class RealmAssignmentBean implements Serializable { // Construire l'assignation RealmAssignmentDTO assignment = RealmAssignmentDTO.builder() - .userId(selectedUserId) - .username(selectedUser.getUsername()) - .email(selectedUser.getEmail()) - .realmName(selectedRealmName) - .isSuperAdmin(false) - .assignedAt(LocalDateTime.now()) - .assignedBy(userSessionBean.getUsername()) - .raison(newAssignment.getRaison()) - .commentaires(newAssignment.getCommentaires()) - .temporaire(newAssignment.getTemporaire() != null && newAssignment.getTemporaire()) - .dateExpiration(newAssignment.getDateExpiration()) - .active(true) - .build(); + .userId(selectedUserId) + .username(selectedUser.getUsername()) + .email(selectedUser.getEmail()) + .realmName(selectedRealmName) + .isSuperAdmin(false) + .assignedAt(LocalDateTime.now()) + .assignedBy(userSessionBean.getUsername()) + .raison(newAssignment.getRaison()) + .commentaires(newAssignment.getCommentaires()) + .temporaire(newAssignment.getTemporaire() != null && newAssignment.getTemporaire()) + .dateExpiration(newAssignment.getDateExpiration()) + .active(true) + .build(); LOGGER.info("Assignation du realm " + selectedRealmName + " à l'utilisateur " + selectedUser.getUsername()); - RealmAssignmentDTO created = realmAssignmentServiceClient.assignRealmToUser(assignment); + jakarta.ws.rs.core.Response response = realmAssignmentServiceClient.assignRealmToUser(assignment); + response.readEntity(RealmAssignmentDTO.class); addSuccessMessage("Realm '" + selectedRealmName + "' assigné avec succès à " + selectedUser.getUsername()); resetForm(); @@ -219,11 +222,13 @@ public class RealmAssignmentBean implements Serializable { return; } - LOGGER.info("Révocation du realm " + assignment.getRealmName() + " pour l'utilisateur " + assignment.getUsername()); + LOGGER.info("Révocation du realm " + assignment.getRealmName() + " pour l'utilisateur " + + assignment.getUsername()); realmAssignmentServiceClient.revokeRealmFromUser(assignment.getUserId(), assignment.getRealmName()); - addSuccessMessage("Accès révoqué pour " + assignment.getUsername() + " au realm '" + assignment.getRealmName() + "'"); + addSuccessMessage( + "Accès révoqué pour " + assignment.getUsername() + " au realm '" + assignment.getRealmName() + "'"); loadAssignments(); } catch (Exception e) { @@ -293,9 +298,9 @@ public class RealmAssignmentBean implements Serializable { } UserDTO user = availableUsers.stream() - .filter(u -> u.getId().equals(userId)) - .findFirst() - .orElse(null); + .filter(u -> u.getId().equals(userId)) + .findFirst() + .orElse(null); String username = user != null ? user.getUsername() : userId; @@ -323,9 +328,9 @@ public class RealmAssignmentBean implements Serializable { */ public void resetForm() { newAssignment = RealmAssignmentDTO.builder() - .active(true) - .temporaire(false) - .build(); + .active(true) + .temporaire(false) + .build(); selectedUserId = null; selectedRealmName = null; } @@ -339,16 +344,18 @@ public class RealmAssignmentBean implements Serializable { } return assignments.stream() - .filter(a -> { - boolean matchUser = filterUserName == null || filterUserName.isEmpty() || - (a.getUsername() != null && a.getUsername().toLowerCase().contains(filterUserName.toLowerCase())); + .filter(a -> { + boolean matchUser = filterUserName == null || filterUserName.isEmpty() || + (a.getUsername() != null + && a.getUsername().toLowerCase().contains(filterUserName.toLowerCase())); - boolean matchRealm = filterRealmName == null || filterRealmName.isEmpty() || - (a.getRealmName() != null && a.getRealmName().toLowerCase().contains(filterRealmName.toLowerCase())); + boolean matchRealm = filterRealmName == null || filterRealmName.isEmpty() || + (a.getRealmName() != null + && a.getRealmName().toLowerCase().contains(filterRealmName.toLowerCase())); - return matchUser && matchRealm; - }) - .collect(Collectors.toList()); + return matchUser && matchRealm; + }) + .collect(Collectors.toList()); } /** @@ -363,8 +370,8 @@ public class RealmAssignmentBean implements Serializable { */ public long getActiveAssignmentsCount() { return assignments.stream() - .filter(RealmAssignmentDTO::isActive) - .count(); + .filter(RealmAssignmentDTO::isActive) + .count(); } /** @@ -372,23 +379,23 @@ public class RealmAssignmentBean implements Serializable { */ public long getSuperAdminsCount() { return assignments.stream() - .filter(RealmAssignmentDTO::isSuperAdmin) - .count(); + .filter(RealmAssignmentDTO::isSuperAdmin) + .count(); } // Méthodes utilitaires pour les messages private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } private void addInfoMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Information", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Information", message)); } } diff --git a/src/main/java/dev/lions/user/manager/client/view/RoleGestionBean.java b/src/main/java/dev/lions/user/manager/client/view/RoleGestionBean.java index 2f072c5..a666521 100644 --- a/src/main/java/dev/lions/user/manager/client/view/RoleGestionBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/RoleGestionBean.java @@ -1,7 +1,7 @@ package dev.lions.user.manager.client.view; -import dev.lions.user.manager.client.service.RealmServiceClient; import dev.lions.user.manager.client.service.RoleServiceClient; +import dev.lions.user.manager.client.service.RealmServiceClient; import dev.lions.user.manager.dto.role.RoleAssignmentDTO; import dev.lions.user.manager.dto.role.RoleDTO; import dev.lions.user.manager.dto.user.UserDTO; @@ -17,7 +17,6 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Logger; @@ -43,21 +42,20 @@ public class RoleGestionBean implements Serializable { @RestClient private RealmServiceClient realmServiceClient; - @Inject - private UserSessionBean userSessionBean; - // Liste des rôles private List realmRoles = new ArrayList<>(); private List clientRoles = new ArrayList<>(); private List allRoles = new ArrayList<>(); private RoleDTO selectedRole; + private String selectedRoleName; // Pour la création/édition private RoleDTO newRole = RoleDTO.builder().build(); private boolean editMode = false; // Filtres - // Par défaut, utiliser le realm lions-user-manager où les rôles métier sont configurés + // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont + // configurés private String realmName = "lions-user-manager"; private String clientName; private TypeRole selectedTypeRole; @@ -83,7 +81,7 @@ public class RoleGestionBean implements Serializable { addErrorMessage("Veuillez sélectionner un realm"); return; } - + try { LOGGER.info("Chargement des rôles Realm pour le realm: " + realmName); realmRoles = roleServiceClient.getAllRealmRoles(realmName); @@ -93,7 +91,8 @@ public class RoleGestionBean implements Serializable { addErrorMessage("Aucun rôle Realm trouvé dans le realm: " + realmName); } } catch (Exception e) { - String errorMsg = "Erreur lors du chargement des rôles Realm pour le realm '" + realmName + "': " + e.getMessage(); + String errorMsg = "Erreur lors du chargement des rôles Realm pour le realm '" + realmName + "': " + + e.getMessage(); LOGGER.severe(errorMsg); LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); addErrorMessage(errorMsg); @@ -111,7 +110,7 @@ public class RoleGestionBean implements Serializable { } try { - clientRoles = roleServiceClient.getAllClientRoles(clientName, realmName); + clientRoles = roleServiceClient.getAllClientRoles(realmName, clientName); updateAllRoles(); LOGGER.info("Chargement de " + clientRoles.size() + " rôles Client"); } catch (Exception e) { @@ -134,7 +133,8 @@ public class RoleGestionBean implements Serializable { */ public void createRealmRole() { try { - RoleDTO created = roleServiceClient.createRealmRole(newRole, realmName); + jakarta.ws.rs.core.Response response = roleServiceClient.createRealmRole(newRole, realmName); + RoleDTO created = response.readEntity(RoleDTO.class); addSuccessMessage("Rôle Realm créé avec succès: " + created.getName()); resetForm(); loadRealmRoles(); @@ -154,7 +154,8 @@ public class RoleGestionBean implements Serializable { } try { - RoleDTO created = roleServiceClient.createClientRole(clientName, newRole, realmName); + jakarta.ws.rs.core.Response response = roleServiceClient.createClientRole(clientName, newRole, realmName); + RoleDTO created = response.readEntity(RoleDTO.class); addSuccessMessage("Rôle Client créé avec succès: " + created.getName()); resetForm(); loadClientRoles(); @@ -202,9 +203,10 @@ public class RoleGestionBean implements Serializable { */ public void assignRoleToUser(String userId, String roleName) { try { - RoleServiceClient.RoleAssignmentRequest request = new RoleServiceClient.RoleAssignmentRequest(); - request.roleNames = List.of(roleName); - roleServiceClient.assignRealmRolesToUser(userId, realmName, request); + dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO request = new dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO( + List.of(roleName)); + + roleServiceClient.assignRealmRoles(userId, realmName, request); addSuccessMessage("Rôle attribué avec succès"); } catch (Exception e) { LOGGER.severe("Erreur lors de l'attribution: " + e.getMessage()); @@ -217,9 +219,10 @@ public class RoleGestionBean implements Serializable { */ public void revokeRoleFromUser(String userId, String roleName) { try { - RoleServiceClient.RoleAssignmentRequest request = new RoleServiceClient.RoleAssignmentRequest(); - request.roleNames = List.of(roleName); - roleServiceClient.revokeRealmRolesFromUser(userId, realmName, request); + dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO request = new dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO( + List.of(roleName)); + + roleServiceClient.revokeRealmRoles(userId, realmName, request); addSuccessMessage("Rôle révoqué avec succès"); } catch (Exception e) { LOGGER.severe("Erreur lors de la révocation: " + e.getMessage()); @@ -234,7 +237,7 @@ public class RoleGestionBean implements Serializable { FacesContext context = FacesContext.getCurrentInstance(); String userId = context.getExternalContext().getRequestParameterMap().get("userId"); String roleName = context.getExternalContext().getRequestParameterMap().get("roleName"); - + if (userId != null && roleName != null) { assignRoleToUser(userId, roleName); } else { @@ -249,7 +252,7 @@ public class RoleGestionBean implements Serializable { FacesContext context = FacesContext.getCurrentInstance(); String userId = context.getExternalContext().getRequestParameterMap().get("userId"); String roleName = context.getExternalContext().getRequestParameterMap().get("roleName"); - + if (userId != null && roleName != null) { revokeRoleFromUser(userId, roleName); } else { @@ -264,14 +267,14 @@ public class RoleGestionBean implements Serializable { if (user == null || user.getRealmRoles() == null || user.getRealmRoles().isEmpty()) { return new ArrayList<>(); } - + if (allRoles == null || allRoles.isEmpty()) { return new ArrayList<>(); } - + return allRoles.stream() - .filter(role -> user.getRealmRoles().contains(role.getName())) - .collect(java.util.stream.Collectors.toList()); + .filter(role -> user.getRealmRoles().contains(role.getName())) + .collect(java.util.stream.Collectors.toList()); } /** @@ -283,58 +286,45 @@ public class RoleGestionBean implements Serializable { } /** - * Charger les realms disponibles depuis Keycloak en fonction des permissions de l'utilisateur + * Charger les realms disponibles + */ + /** + * Charger les realms disponibles depuis Keycloak */ private void loadRealms() { try { - // Récupérer tous les realms depuis Keycloak - List allRealms = realmServiceClient.getAllRealms(); - - if (allRealms == null || allRealms.isEmpty()) { - LOGGER.warning("Aucun realm trouvé dans Keycloak"); - availableRealms = Collections.emptyList(); - return; - } - - List authorizedRealms = userSessionBean.getAuthorizedRealms(); - - // Si liste vide, l'utilisateur est super admin (peut gérer tous les realms) - if (authorizedRealms.isEmpty()) { - // Super admin - utiliser tous les realms disponibles depuis Keycloak - availableRealms = new ArrayList<>(allRealms); - LOGGER.info("Super admin détecté - " + availableRealms.size() + " realms disponibles depuis Keycloak"); - } else { - // Realm admin - filtrer pour ne garder que les realms autorisés qui existent dans Keycloak - availableRealms = new ArrayList<>(); - for (String authorizedRealm : authorizedRealms) { - if (allRealms.contains(authorizedRealm)) { - availableRealms.add(authorizedRealm); - } - } - LOGGER.info("Realms autorisés pour l'utilisateur: " + availableRealms.size()); - - // Définir le premier realm autorisé comme realm par défaut - if (!availableRealms.isEmpty() && !availableRealms.contains(realmName)) { - realmName = availableRealms.get(0); - } - } + availableRealms = realmServiceClient.getAllRealms(); + LOGGER.info("Realms chargés: " + availableRealms); } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); - // Fallback: liste vide plutôt que des données fictives - availableRealms = Collections.emptyList(); + LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage()); + // Fallback en cas d'erreur + availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow"); + } + } + + /** + * Charger les rôles du realm spécifié. + * Cette méthode sert de point d'entrée pour la page d'édition. + * + * @param realm Le nom du realm dont il faut charger les rôles + */ + public void loadRolesForUser(String realm) { + if (realm != null && !realm.isEmpty()) { + this.realmName = realm; + loadRealmRoles(); + } else { + // Utiliser le realm par défaut si non fourni + loadRealmRoles(); } } - // Méthodes utilitaires private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/SessionMonitorBean.java b/src/main/java/dev/lions/user/manager/client/view/SessionMonitorBean.java index c234f2a..21f7c36 100644 --- a/src/main/java/dev/lions/user/manager/client/view/SessionMonitorBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/SessionMonitorBean.java @@ -1,9 +1,7 @@ package dev.lions.user.manager.client.view; import jakarta.enterprise.context.SessionScoped; -import jakarta.inject.Inject; import jakarta.inject.Named; -import org.eclipse.microprofile.jwt.JsonWebToken; import java.io.Serializable; import java.time.Instant; @@ -27,9 +25,6 @@ public class SessionMonitorBean implements Serializable { // Temps d'inactivité maximum en secondes (30 minutes par défaut) private static final long DEFAULT_INACTIVITY_TIMEOUT = 1800; - @Inject - private JsonWebToken jwt; - private Instant lastActivityTime; private long inactivityTimeout = DEFAULT_INACTIVITY_TIMEOUT; @@ -94,7 +89,8 @@ public class SessionMonitorBean implements Serializable { */ public int getSessionProgressPercent() { long inactivitySeconds = getInactivitySeconds(); - if (inactivityTimeout == 0) return 0; + if (inactivityTimeout == 0) + return 0; int percent = (int) ((inactivitySeconds * 100) / inactivityTimeout); return Math.min(100, Math.max(0, percent)); diff --git a/src/main/java/dev/lions/user/manager/client/view/SyncDashboardBean.java b/src/main/java/dev/lions/user/manager/client/view/SyncDashboardBean.java new file mode 100644 index 0000000..1f1edb8 --- /dev/null +++ b/src/main/java/dev/lions/user/manager/client/view/SyncDashboardBean.java @@ -0,0 +1,129 @@ +package dev.lions.user.manager.client.view; + +import dev.lions.user.manager.client.service.SyncServiceClient; +import dev.lions.user.manager.dto.sync.HealthStatusDTO; +import dev.lions.user.manager.dto.sync.SyncResultDTO; +import jakarta.annotation.PostConstruct; +import jakarta.faces.application.FacesMessage; +import jakarta.faces.context.FacesContext; +import jakarta.faces.view.ViewScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import org.eclipse.microprofile.rest.client.inject.RestClient; + +import java.io.Serializable; +import java.util.logging.Logger; + +@Named +@ViewScoped +public class SyncDashboardBean implements Serializable { + + private static final Logger LOGGER = Logger.getLogger(SyncDashboardBean.class.getName()); + + @Inject + @RestClient + SyncServiceClient syncService; + + private HealthStatusDTO keycloakStatus; + private String syncMessage; + private String targetRealm = "lions-user-manager"; // Default realm matches OIDC config + + @PostConstruct + public void init() { + checkKeycloakStatus(); + } + + public void checkKeycloakStatus() { + try { + this.keycloakStatus = syncService.checkKeycloakHealth(); + } catch (Exception e) { + LOGGER.severe("Erreur lors de la vérification de l'état de Keycloak: " + e.getMessage()); + this.keycloakStatus = new HealthStatusDTO(); + this.keycloakStatus.setOverallHealthy(false); + this.keycloakStatus.setErrorMessage("Erreur de connexion: " + e.getMessage()); + } + } + + public void syncUsers() { + try { + SyncResultDTO result = syncService.syncUsers(targetRealm); + handleSyncResult("Utilisateurs", result); + } catch (Exception e) { + LOGGER.severe("Erreur lors de la synchronisation des utilisateurs: " + e.getMessage()); + addMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Echec de la synchronisation des utilisateurs: " + e.getMessage()); + } + } + + public void syncRoles() { + try { + // Sychronize realm roles + SyncResultDTO result = syncService.syncRoles(targetRealm, null); + handleSyncResult("Rôles", result); + } catch (Exception e) { + LOGGER.severe("Erreur lors de la synchronisation des rôles: " + e.getMessage()); + addMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Echec de la synchronisation des rôles: " + e.getMessage()); + } + } + + private void handleSyncResult(String type, SyncResultDTO result) { + String msg = result.isSuccess() + ? "Synchronisation réussie. " + type + " synchronisés : " + + ("Utilisateurs".equals(type) ? result.getUsersCount() : result.getRealmRolesCount()) + : result.getErrorMessage(); + + if (result.isSuccess()) { + addMessage(FacesMessage.SEVERITY_INFO, "Succès", msg); + } else { + addMessage(FacesMessage.SEVERITY_WARN, "Attention", type + ": " + msg); + } + this.syncMessage = msg; + } + + private void addMessage(FacesMessage.Severity severity, String summary, String detail) { + FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, summary, detail)); + } + + // Getters and Setters + public HealthStatusDTO getKeycloakStatus() { + return keycloakStatus; + } + + public void setKeycloakStatus(HealthStatusDTO keycloakStatus) { + this.keycloakStatus = keycloakStatus; + } + + // Convenience methods for view + public String getKeycloakStatusLabel() { + return (keycloakStatus != null && keycloakStatus.isOverallHealthy()) ? "UP" : "DOWN"; + } + + public String getKeycloakStatusMessage() { + if (keycloakStatus == null) + return "Unknown status"; + if (keycloakStatus.isOverallHealthy()) + return "Keycloak est accessible."; + return keycloakStatus.getErrorMessage() != null ? keycloakStatus.getErrorMessage() : "Erreur inconnue"; + } + + public String getKeycloakVersion() { + return (keycloakStatus != null) ? keycloakStatus.getKeycloakVersion() : "N/A"; + } + + public String getSyncMessage() { + return syncMessage; + } + + public void setSyncMessage(String syncMessage) { + this.syncMessage = syncMessage; + } + + public String getTargetRealm() { + return targetRealm; + } + + public void setTargetRealm(String targetRealm) { + this.targetRealm = targetRealm; + } +} diff --git a/src/main/java/dev/lions/user/manager/client/view/UserCreationBean.java b/src/main/java/dev/lions/user/manager/client/view/UserCreationBean.java index 7b47821..057b196 100644 --- a/src/main/java/dev/lions/user/manager/client/view/UserCreationBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/UserCreationBean.java @@ -1,6 +1,5 @@ package dev.lions.user.manager.client.view; -import dev.lions.user.manager.client.service.RealmServiceClient; import dev.lions.user.manager.client.service.UserServiceClient; import dev.lions.user.manager.dto.user.UserDTO; import dev.lions.user.manager.enums.user.StatutUser; @@ -15,7 +14,6 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Logger; @@ -37,13 +35,10 @@ public class UserCreationBean implements Serializable { @RestClient private UserServiceClient userServiceClient; - @Inject - @RestClient - private RealmServiceClient realmServiceClient; - private UserDTO newUser = UserDTO.builder().build(); - // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont configurés - private String realmName = "lions-user-manager"; + // Le realm "master" est le realm d'administration qui permet de gérer tous les + // autres realms + private String realmName = "master"; private String password; private String passwordConfirm; @@ -82,13 +77,13 @@ public class UserCreationBean implements Serializable { try { // Créer l'utilisateur - UserDTO createdUser = userServiceClient.createUser(newUser, realmName); + jakarta.ws.rs.core.Response response = userServiceClient.createUser(newUser, realmName); + UserDTO createdUser = response.readEntity(UserDTO.class); // Définir le mot de passe - UserServiceClient.PasswordResetRequest passwordRequest = new UserServiceClient.PasswordResetRequest(); - passwordRequest.password = password; - passwordRequest.temporary = true; - userServiceClient.resetPassword(createdUser.getId(), realmName, passwordRequest); + dev.lions.user.manager.dto.user.PasswordResetRequestDTO request = new dev.lions.user.manager.dto.user.PasswordResetRequestDTO( + password, false); + userServiceClient.resetPassword(createdUser.getId(), realmName, request); addSuccessMessage("Utilisateur créé avec succès: " + createdUser.getUsername()); resetForm(); @@ -121,68 +116,23 @@ public class UserCreationBean implements Serializable { } /** - * Valider la correspondance des mots de passe en temps réel - */ - public void validatePasswordMatch() { - FacesContext context = FacesContext.getCurrentInstance(); - - // Vérifier que les deux champs sont remplis - if (password != null && !password.isEmpty() && - passwordConfirm != null && !passwordConfirm.isEmpty()) { - - // Vérifier la correspondance - if (!password.equals(passwordConfirm)) { - context.addMessage("formUserCreation:passwordConfirm", - new FacesMessage(FacesMessage.SEVERITY_ERROR, - "Erreur", - "Les mots de passe ne correspondent pas")); - } else { - // Succès - afficher message de confirmation - context.addMessage("formUserCreation:passwordConfirm", - new FacesMessage(FacesMessage.SEVERITY_INFO, - "Validé", - "Les mots de passe correspondent")); - } - } - } - - /** - * Charger les realms disponibles depuis Keycloak + * Charger les realms disponibles */ private void loadRealms() { - try { - LOGGER.info("Chargement des realms disponibles depuis Keycloak"); - List realms = realmServiceClient.getAllRealms(); - - if (realms == null || realms.isEmpty()) { - LOGGER.warning("Aucun realm trouvé dans Keycloak"); - availableRealms = Collections.emptyList(); - } else { - availableRealms = new ArrayList<>(realms); - LOGGER.info("Realms disponibles chargés depuis Keycloak: " + availableRealms.size()); - - // Définir le premier realm comme realm par défaut si aucun n'est sélectionné - if (!availableRealms.isEmpty() && (realmName == null || realmName.isEmpty())) { - realmName = availableRealms.get(0); - } - } - } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); - // Fallback: liste vide plutôt que des données fictives - availableRealms = Collections.emptyList(); - } + // TODO: Implémenter la récupération des realms depuis Keycloak + // Le realm "master" est le realm d'administration qui permet de gérer tous les + // autres realms + availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow"); } // Méthodes utilitaires private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/UserListBean.java b/src/main/java/dev/lions/user/manager/client/view/UserListBean.java index c2b63ba..da4c865 100644 --- a/src/main/java/dev/lions/user/manager/client/view/UserListBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/UserListBean.java @@ -8,7 +8,6 @@ import dev.lions.user.manager.dto.user.UserSearchResultDTO; import dev.lions.user.manager.enums.user.StatutUser; import jakarta.annotation.PostConstruct; import jakarta.faces.application.FacesMessage; -import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; import jakarta.faces.event.ActionEvent; import jakarta.faces.view.ViewScoped; @@ -16,13 +15,16 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import lombok.Data; import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.primefaces.PrimeFaces; import org.primefaces.event.data.PageEvent; +import org.primefaces.model.FilterMeta; +import org.primefaces.model.LazyDataModel; +import org.primefaces.model.SortMeta; import java.io.Serializable; -import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.logging.Logger; /** @@ -52,18 +54,16 @@ public class UserListBean implements Serializable { @RestClient private RealmServiceClient realmServiceClient; - @Inject - private UserSessionBean userSessionBean; - // Propriétés pour la liste - private List users = new ArrayList<>(); + private LazyDataModel users; private UserDTO selectedUser; private List selectedUsers = new ArrayList<>(); // Propriétés pour la recherche private UserSearchCriteriaDTO searchCriteria = UserSearchCriteriaDTO.builder().build(); private String searchText; - // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont configurés + // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont + // configurés private String realmName = "lions-user-manager"; private StatutUser selectedStatut; @@ -77,63 +77,84 @@ public class UserListBean implements Serializable { private List statutOptions = List.of(StatutUser.values()); private List availableRealms = new ArrayList<>(); - // Résultats de l'import CSV - private dev.lions.user.manager.dto.importexport.ImportResultDTO lastImportResult; + // Champs pour réinitialisation mot de passe + private String newPassword; + private String newPasswordConfirm; @PostConstruct public void init() { LOGGER.info("Initialisation de UserListBean"); - loadUsers(); loadRealms(); + + users = new LazyDataModel() { + @Override + public String getRowKey(UserDTO user) { + return user.getId(); + } + + @Override + public UserDTO getRowData(String rowKey) { + List list = (List) getWrappedData(); + if (list != null) { + for (UserDTO user : list) { + if (user.getId().equals(rowKey)) { + return user; + } + } + } + return null; + } + + @Override + public int count(Map filterBy) { + return (int) totalRecords; + } + + @Override + public List load(int first, int pageSize, Map sortBy, + Map filterBy) { + try { + int page = first / pageSize; + + UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder() + .realmName(realmName) + .searchTerm(searchText) + .statut(selectedStatut) + .page(page) + .pageSize(pageSize) + .build(); + + UserSearchResultDTO result = userServiceClient.searchUsers(criteria); + List data = result.getUsers() != null ? result.getUsers() : new ArrayList<>(); + + long total = result.getTotalCount() != null ? result.getTotalCount() : 0; + this.setRowCount((int) total); + totalRecords = total; + + return data; + } catch (Exception e) { + LOGGER.severe("Erreur loading: " + e.getMessage()); + return new ArrayList<>(); + } + } + }; } /** * Charger la liste des utilisateurs + * (Deprecated: Utiliser LazyDataModel) */ public void loadUsers() { - try { - UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder() - .realmName(realmName) - .page(currentPage) - .pageSize(pageSize) - .build(); - - UserSearchResultDTO result = userServiceClient.searchUsers(criteria); - this.users = result.getUsers() != null ? result.getUsers() : new ArrayList<>(); - this.totalRecords = result.getTotalCount() != null ? result.getTotalCount() : 0; - this.totalPages = (int) Math.ceil((double) totalRecords / pageSize); - - LOGGER.info("Chargement de " + users.size() + " utilisateurs"); - } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des utilisateurs: " + e.getMessage()); - addErrorMessage("Erreur lors du chargement des utilisateurs: " + e.getMessage()); - } + // La méthode load du LazyDataModel est appelée automatiquement par le composant } /** * Rechercher des utilisateurs */ public void search() { - try { - currentPage = 0; // Réinitialiser à la première page - - UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder() - .realmName(realmName) - .searchTerm(searchText) - .statut(selectedStatut) - .page(currentPage) - .pageSize(pageSize) - .build(); - - UserSearchResultDTO result = userServiceClient.searchUsers(criteria); - this.users = result.getUsers() != null ? result.getUsers() : new ArrayList<>(); - this.totalRecords = result.getTotalCount() != null ? result.getTotalCount() : 0; - this.totalPages = (int) Math.ceil((double) totalRecords / pageSize); - - addSuccessMessage("Recherche effectuée: " + totalRecords + " résultat(s) trouvé(s)"); - } catch (Exception e) { - LOGGER.severe("Erreur lors de la recherche: " + e.getMessage()); - addErrorMessage("Erreur lors de la recherche: " + e.getMessage()); + currentPage = 0; + if (PrimeFaces.current().isAjaxRequest()) { + PrimeFaces.current().executeScript("PF('userTableWidget').getPaginator().setPage(0);"); } } @@ -144,25 +165,31 @@ public class UserListBean implements Serializable { searchText = null; selectedStatut = null; currentPage = 0; - loadUsers(); + if (PrimeFaces.current().isAjaxRequest()) { + PrimeFaces.current().executeScript("PF('userTableWidget').getPaginator().setPage(0);"); + } } /** - * Gérer les événements de pagination du datatable + * Réinitialiser le mot de passe */ - public void onPageChange(PageEvent event) { - try { - int page = event.getPage(); - - currentPage = page; - - LOGGER.info("Changement de page: page=" + currentPage + ", rows=" + pageSize); - - // Recharger les données avec la nouvelle page - loadUsers(); - } catch (Exception e) { - LOGGER.severe("Erreur lors du changement de page: " + e.getMessage()); - addErrorMessage("Erreur lors du changement de page: " + e.getMessage()); + public void resetPassword(String userId) { + if (newPassword != null && !newPassword.isEmpty() && newPassword.equals(newPasswordConfirm)) { + try { + // Utilisation du DTO pour la demande de réinitialisation + dev.lions.user.manager.dto.user.PasswordResetRequestDTO request = new dev.lions.user.manager.dto.user.PasswordResetRequestDTO( + newPassword, false); + userServiceClient.resetPassword(userId, realmName, request); + addSuccessMessage("Mot de passe réinitialisé avec succès"); + // Clear fields + newPassword = null; + newPasswordConfirm = null; + } catch (Exception e) { + LOGGER.severe("Erreur lors de la réinitialisation du mot de passe: " + e.getMessage()); + addErrorMessage("Erreur lors de la réinitialisation: " + e.getMessage()); + } + } else { + addErrorMessage("Les mots de passe sont invalides ou ne correspondent pas"); } } @@ -201,14 +228,10 @@ public class UserListBean implements Serializable { */ public void activateUser(String userId) { try { - LOGGER.info("Activation de l'utilisateur: " + userId + " dans le realm: " + realmName); userServiceClient.activateUser(userId, realmName); addSuccessMessage("Utilisateur activé avec succès"); - // Recharger les données - loadUsers(); } catch (Exception e) { LOGGER.severe("Erreur lors de l'activation: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); addErrorMessage("Erreur lors de l'activation: " + e.getMessage()); } } @@ -218,14 +241,10 @@ public class UserListBean implements Serializable { */ public void deactivateUser(String userId) { try { - LOGGER.info("Désactivation de l'utilisateur: " + userId + " dans le realm: " + realmName); - userServiceClient.deactivateUser(userId, realmName); + userServiceClient.deactivateUser(userId, realmName, "Désactivé par l'administrateur"); addSuccessMessage("Utilisateur désactivé avec succès"); - // Recharger les données - loadUsers(); } catch (Exception e) { LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); addErrorMessage("Erreur lors de la désactivation: " + e.getMessage()); } } @@ -235,14 +254,10 @@ public class UserListBean implements Serializable { */ public void deleteUser(String userId) { try { - LOGGER.info("Suppression de l'utilisateur: " + userId + " dans le realm: " + realmName); - userServiceClient.deleteUser(userId, realmName); + userServiceClient.deleteUser(userId, realmName, false); addSuccessMessage("Utilisateur supprimé avec succès"); - // Recharger les données - loadUsers(); } catch (Exception e) { LOGGER.severe("Erreur lors de la suppression: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); addErrorMessage("Erreur lors de la suppression: " + e.getMessage()); } } @@ -264,24 +279,27 @@ public class UserListBean implements Serializable { * Obtenir le nombre d'utilisateurs actifs */ public long getActiveUsersCount() { - if (users == null || users.isEmpty()) { - return 0; - } - return users.stream() - .filter(user -> user.getEnabled() != null && user.getEnabled()) - .count(); + return calculateStatusCount(true); } /** * Obtenir le nombre d'utilisateurs désactivés */ public long getDisabledUsersCount() { - if (users == null || users.isEmpty()) { + return calculateStatusCount(false); + } + + // Helper for counts + private long calculateStatusCount(boolean enabled) { + if (users == null) + return 0; + List list = (List) users.getWrappedData(); + if (list == null || list.isEmpty()) { return 0; } - return users.stream() - .filter(user -> user.getEnabled() != null && !user.getEnabled()) - .count(); + return list.stream() + .filter(user -> user.getEnabled() != null && user.getEnabled() == enabled) + .count(); } /** @@ -313,177 +331,33 @@ public class UserListBean implements Serializable { } /** - * Exporter les utilisateurs en CSV + * Exporter vers CSV (placeholder) */ public void exportToCSV() { - try { - if (realmName == null || realmName.isEmpty()) { - addErrorMessage("Veuillez sélectionner un realm"); - return; - } - - String csv = userServiceClient.exportUsersToCSV(realmName); - - // Télécharger le fichier CSV - FacesContext facesContext = FacesContext.getCurrentInstance(); - ExternalContext externalContext = facesContext.getExternalContext(); - - String filename = "users_export_" + - LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmmss")) + - ".csv"; - - externalContext.setResponseContentType("text/csv; charset=UTF-8"); - externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); - - java.io.OutputStream output = externalContext.getResponseOutputStream(); - output.write(csv.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - output.flush(); - - facesContext.responseComplete(); - LOGGER.info("Export CSV généré avec succès: " + filename); - } catch (java.io.IOException e) { - LOGGER.severe("Erreur I/O lors de l'export CSV: " + e.getMessage()); - addErrorMessage("Erreur lors du téléchargement: " + e.getMessage()); - } catch (Exception e) { - LOGGER.severe("Erreur lors de l'export CSV: " + e.getMessage()); - addErrorMessage("Erreur lors de l'export: " + e.getMessage()); - } + addSuccessMessage("Fonctionnalité d'export en cours de développement"); } /** - * Télécharger un template CSV pour l'import d'utilisateurs - */ - public void downloadCSVTemplate() { - try { - // Créer un template CSV avec des exemples - StringBuilder csvTemplate = new StringBuilder(); - csvTemplate.append("username,prenom,nom,email\n"); - csvTemplate.append("jdupont,Jean,Dupont,jean.dupont@example.com\n"); - csvTemplate.append("mmartin,Marie,Martin,marie.martin@example.com\n"); - csvTemplate.append("pbernard,Pierre,Bernard,pierre.bernard@example.com\n"); - - FacesContext facesContext = FacesContext.getCurrentInstance(); - ExternalContext externalContext = facesContext.getExternalContext(); - - String filename = "template_import_users.csv"; - - externalContext.setResponseContentType("text/csv; charset=UTF-8"); - externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); - - java.io.OutputStream output = externalContext.getResponseOutputStream(); - output.write(csvTemplate.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8)); - output.flush(); - - facesContext.responseComplete(); - LOGGER.info("Template CSV téléchargé avec succès: " + filename); - } catch (java.io.IOException e) { - LOGGER.severe("Erreur I/O lors du téléchargement du template CSV: " + e.getMessage()); - addErrorMessage("Erreur lors du téléchargement du template: " + e.getMessage()); - } catch (Exception e) { - LOGGER.severe("Erreur lors du téléchargement du template CSV: " + e.getMessage()); - addErrorMessage("Erreur lors du téléchargement: " + e.getMessage()); - } - } - - /** - * Importer des utilisateurs depuis un fichier CSV - * Cette méthode sera appelée par le gestionnaire d'upload de fichier + * Importer des utilisateurs (placeholder) */ public void importUsers() { - addInfoMessage("Veuillez utiliser le bouton 'Parcourir' pour sélectionner un fichier CSV"); + addSuccessMessage("Fonctionnalité d'import en cours de développement"); } /** - * Gérer l'upload de fichier CSV pour import + * Charger les realms disponibles */ - public void handleFileUpload(org.primefaces.event.FileUploadEvent event) { - try { - if (realmName == null || realmName.isEmpty()) { - addErrorMessage("Veuillez sélectionner un realm avant d'importer"); - return; - } - - if (event.getFile() == null) { - addErrorMessage("Aucun fichier sélectionné"); - return; - } - - // Lire le contenu du fichier - String csvContent = new String(event.getFile().getContent(), java.nio.charset.StandardCharsets.UTF_8); - - if (csvContent.trim().isEmpty()) { - addErrorMessage("Le fichier CSV est vide"); - return; - } - - // Appeler l'API d'import - dev.lions.user.manager.dto.importexport.ImportResultDTO result = - userServiceClient.importUsersFromCSV(realmName, csvContent); - - // Stocker le résultat pour l'affichage dans le dialog - this.lastImportResult = result; - - // Afficher le résultat - LOGGER.info("Import terminé: " + result.getMessage()); - - if (result.getErrorCount() == 0) { - addSuccessMessage(result.getMessage()); - } else { - addWarningMessage(result.getMessage()); - } - - // Ouvrir le dialog de résultats détaillés - org.primefaces.PrimeFaces.current().executeScript("PF('importResultDialog').show();"); - - loadUsers(); // Recharger la liste - - } catch (Exception e) { - LOGGER.severe("Erreur lors de l'import: " + e.getMessage()); - addErrorMessage("Erreur lors de l'import: " + e.getMessage()); - } - } - /** - * Charger les realms disponibles depuis Keycloak en fonction des permissions de l'utilisateur + * Charger les realms disponibles depuis Keycloak */ private void loadRealms() { try { - // Récupérer tous les realms depuis Keycloak - List allRealms = realmServiceClient.getAllRealms(); - - if (allRealms == null || allRealms.isEmpty()) { - LOGGER.warning("Aucun realm trouvé dans Keycloak"); - availableRealms = Collections.emptyList(); - return; - } - - List authorizedRealms = userSessionBean.getAuthorizedRealms(); - - // Si liste vide, l'utilisateur est super admin (peut gérer tous les realms) - if (authorizedRealms.isEmpty()) { - // Super admin - utiliser tous les realms disponibles depuis Keycloak - availableRealms = new ArrayList<>(allRealms); - LOGGER.info("Super admin détecté - " + availableRealms.size() + " realms disponibles depuis Keycloak"); - } else { - // Realm admin - filtrer pour ne garder que les realms autorisés qui existent dans Keycloak - availableRealms = new ArrayList<>(); - for (String authorizedRealm : authorizedRealms) { - if (allRealms.contains(authorizedRealm)) { - availableRealms.add(authorizedRealm); - } - } - LOGGER.info("Realms autorisés pour l'utilisateur: " + availableRealms.size()); - - // Définir le premier realm autorisé comme realm par défaut - if (!availableRealms.isEmpty() && !availableRealms.contains(realmName)) { - realmName = availableRealms.get(0); - } - } + availableRealms = realmServiceClient.getAllRealms(); + LOGGER.info("Realms chargés: " + availableRealms); } catch (Exception e) { - LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); - // Fallback: liste vide plutôt que des données fictives - availableRealms = Collections.emptyList(); + LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage()); + // Fallback en cas d'erreur + availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow"); } } @@ -511,22 +385,11 @@ public class UserListBean implements Serializable { // Méthodes utilitaires pour les messages private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); - } - - private void addInfoMessage(String message) { - FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Information", message)); - } - - private void addWarningMessage(String message) { - FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_WARN, "Avertissement", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/UserProfilBean.java b/src/main/java/dev/lions/user/manager/client/view/UserProfilBean.java index 1c50aba..a89f15f 100644 --- a/src/main/java/dev/lions/user/manager/client/view/UserProfilBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/UserProfilBean.java @@ -32,12 +32,9 @@ public class UserProfilBean implements Serializable { @RestClient private UserServiceClient userServiceClient; - @Inject - private RoleGestionBean roleGestionBean; - private UserDTO user; private String userId; - // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont configurés + // Le realm "lions-user-manager" est le realm par défaut private String realmName = "lions-user-manager"; private boolean editMode = false; @@ -47,29 +44,21 @@ public class UserProfilBean implements Serializable { @PostConstruct public void init() { - // Récupérer l'ID et le realm depuis les paramètres de requête - FacesContext facesContext = FacesContext.getCurrentInstance(); - java.util.Map params = facesContext.getExternalContext().getRequestParameterMap(); - - userId = params.get("userId"); - String realmParam = params.get("realm"); - - if (realmParam != null && !realmParam.isEmpty()) { - realmName = realmParam; - } + // Récupérer l'ID depuis les paramètres de requête + userId = FacesContext.getCurrentInstance().getExternalContext() + .getRequestParameterMap().get("userId"); - LOGGER.info("Initialisation de UserProfilBean avec userId: " + userId + ", realm: " + realmName); + // Récupérer le realm depuis les paramètres de requête (si présent) + String realmParam = FacesContext.getCurrentInstance().getExternalContext() + .getRequestParameterMap().get("realm"); + if (realmParam != null && !realmParam.isEmpty()) { + this.realmName = realmParam; + } if (userId != null && !userId.isEmpty()) { loadUser(); - // Charger les rôles disponibles - if (roleGestionBean != null) { - roleGestionBean.setRealmName(realmName); - roleGestionBean.loadRealmRoles(); - } } else { - LOGGER.warning("Aucun userId fourni dans les paramètres de requête"); - addErrorMessage("Aucun ID d'utilisateur fourni. Accédez à cette page depuis la liste des utilisateurs."); + LOGGER.warning("Aucun userId fourni dans les paramètres"); } } @@ -112,15 +101,11 @@ public class UserProfilBean implements Serializable { */ public void updateUser() { try { - LOGGER.info("Mise à jour de l'utilisateur: " + userId + " dans le realm: " + realmName); user = userServiceClient.updateUser(userId, user, realmName); editMode = false; addSuccessMessage("Utilisateur mis à jour avec succès"); - // Recharger les données pour s'assurer qu'elles sont à jour - loadUser(); } catch (Exception e) { LOGGER.severe("Erreur lors de la mise à jour: " + e.getMessage()); - LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e); addErrorMessage("Erreur lors de la mise à jour: " + e.getMessage()); } } @@ -140,9 +125,8 @@ public class UserProfilBean implements Serializable { } try { - UserServiceClient.PasswordResetRequest request = new UserServiceClient.PasswordResetRequest(); - request.password = newPassword; - request.temporary = true; + dev.lions.user.manager.dto.user.PasswordResetRequestDTO request = new dev.lions.user.manager.dto.user.PasswordResetRequestDTO( + newPassword, false); userServiceClient.resetPassword(userId, realmName, request); newPassword = null; newPasswordConfirm = null; @@ -172,7 +156,7 @@ public class UserProfilBean implements Serializable { */ public void deactivateUser() { try { - userServiceClient.deactivateUser(userId, realmName); + userServiceClient.deactivateUser(userId, realmName, "Désactivé depuis le profil utilisateur"); loadUser(); // Recharger pour mettre à jour le statut addSuccessMessage("Utilisateur désactivé avec succès"); } catch (Exception e) { @@ -194,6 +178,38 @@ public class UserProfilBean implements Serializable { } } + /** + * Supprimer l'utilisateur + */ + public void deleteUser() { + try { + userServiceClient.deleteUser(userId, realmName, false); + addSuccessMessage("Utilisateur supprimé avec succès"); + FacesContext.getCurrentInstance().getExternalContext().redirect("list.xhtml"); + } catch (Exception e) { + LOGGER.severe("Erreur lors de la suppression: " + e.getMessage()); + addErrorMessage("Erreur lors de la suppression: " + e.getMessage()); + } + } + + // Méthodes compatibles avec user-actions.xhtml (qui passe l'ID en paramètre) + + public void activateUser(String userId) { + activateUser(); + } + + public void deactivateUser(String userId) { + deactivateUser(); + } + + public void resetPassword(String userId) { + resetPassword(); + } + + public void deleteUser(String userId) { + deleteUser(); + } + /** * Déconnecter toutes les sessions */ @@ -207,15 +223,18 @@ public class UserProfilBean implements Serializable { } } + public void logoutAllSessions(String userId) { + logoutAllSessions(); + } + // Méthodes utilitaires private void addSuccessMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message)); } private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, - new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message)); } } - diff --git a/src/main/java/dev/lions/user/manager/client/view/UserSessionBean.java b/src/main/java/dev/lions/user/manager/client/view/UserSessionBean.java index 7258b18..96a4155 100644 --- a/src/main/java/dev/lions/user/manager/client/view/UserSessionBean.java +++ b/src/main/java/dev/lions/user/manager/client/view/UserSessionBean.java @@ -1,6 +1,5 @@ package dev.lions.user.manager.client.view; -import dev.lions.user.manager.client.service.RealmAssignmentServiceClient; import io.quarkus.oidc.IdToken; import io.quarkus.oidc.OidcSession; import io.quarkus.security.identity.SecurityIdentity; @@ -12,11 +11,8 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import lombok.Data; import org.eclipse.microprofile.jwt.JsonWebToken; -import org.eclipse.microprofile.rest.client.inject.RestClient; import java.io.Serializable; -import java.util.Collections; -import java.util.List; import java.util.logging.Logger; /** @@ -43,10 +39,6 @@ public class UserSessionBean implements Serializable { @Inject OidcSession oidcSession; - @Inject - @RestClient - RealmAssignmentServiceClient realmAssignmentServiceClient; - // Informations utilisateur private String username; private String email; @@ -81,7 +73,7 @@ public class UserSessionBean implements Serializable { // Prénom et nom firstName = idToken.getClaim("given_name"); lastName = idToken.getClaim("family_name"); - + // Nom complet fullName = idToken.getClaim("name"); if (fullName == null || fullName.trim().isEmpty()) { @@ -127,7 +119,7 @@ public class UserSessionBean implements Serializable { String[] parts = name.trim().split("\\s+"); if (parts.length >= 2) { return String.valueOf(parts[0].charAt(0)).toUpperCase() + - String.valueOf(parts[1].charAt(0)).toUpperCase(); + String.valueOf(parts[1].charAt(0)).toUpperCase(); } else if (parts.length == 1) { String part = parts[0]; if (part.length() >= 2) { @@ -178,7 +170,8 @@ public class UserSessionBean implements Serializable { */ private String getMainRole() { try { - if (securityIdentity != null && securityIdentity.getRoles() != null && !securityIdentity.getRoles().isEmpty()) { + if (securityIdentity != null && securityIdentity.getRoles() != null + && !securityIdentity.getRoles().isEmpty()) { // Prioriser certains rôles java.util.Set roleSet = securityIdentity.getRoles(); if (roleSet.contains("admin")) { @@ -218,90 +211,6 @@ public class UserSessionBean implements Serializable { return false; } - // ==================== Gestion des realms autorisés ==================== - - /** - * Vérifie si l'utilisateur est super admin (peut gérer tous les realms) - */ - public boolean isSuperAdmin() { - try { - if (getSubject() == null || "Non disponible".equals(getSubject())) { - return false; - } - - RealmAssignmentServiceClient.AuthorizedRealmsResponse response = - realmAssignmentServiceClient.getAuthorizedRealms(getSubject()); - - return response != null && response.isSuperAdmin; - } catch (Exception e) { - LOGGER.warning("Erreur lors de la vérification du statut super admin: " + e.getMessage()); - // En cas d'erreur réseau, vérifier le rôle local - return hasRole("admin"); - } - } - - /** - * Récupère la liste des realms que l'utilisateur peut administrer - * Retourne une liste vide si l'utilisateur est super admin (peut tout gérer) - */ - public List getAuthorizedRealms() { - try { - if (getSubject() == null || "Non disponible".equals(getSubject())) { - return Collections.emptyList(); - } - - RealmAssignmentServiceClient.AuthorizedRealmsResponse response = - realmAssignmentServiceClient.getAuthorizedRealms(getSubject()); - - if (response == null) { - return Collections.emptyList(); - } - - // Si super admin, retourner liste vide (convention: peut tout gérer) - if (response.isSuperAdmin) { - return Collections.emptyList(); - } - - return response.realms != null ? response.realms : Collections.emptyList(); - } catch (Exception e) { - LOGGER.warning("Erreur lors de la récupération des realms autorisés: " + e.getMessage()); - // En cas d'erreur, si admin local, retourner liste vide (peut tout gérer) - if (hasRole("admin")) { - return Collections.emptyList(); - } - return Collections.emptyList(); - } - } - - /** - * Vérifie si l'utilisateur peut administrer un realm spécifique - */ - public boolean canManageRealm(String realmName) { - try { - if (realmName == null || realmName.isBlank()) { - return false; - } - - if (getSubject() == null || "Non disponible".equals(getSubject())) { - return false; - } - - // Super admin peut tout gérer - if (isSuperAdmin()) { - return true; - } - - RealmAssignmentServiceClient.CheckResponse response = - realmAssignmentServiceClient.canManageRealm(getSubject(), realmName); - - return response != null && response.canManage; - } catch (Exception e) { - LOGGER.warning("Erreur lors de la vérification d'accès au realm " + realmName + ": " + e.getMessage()); - // En cas d'erreur réseau, vérifier le rôle local - return hasRole("admin"); - } - } - /** * Obtenir l'issuer du token OIDC */ @@ -436,9 +345,10 @@ public class UserSessionBean implements Serializable { externalContext.invalidateSession(); // Rediriger vers l'endpoint de logout OIDC de Quarkus - // Quarkus gère automatiquement la redirection vers Keycloak pour la déconnexion complète - String logoutUrl = "/auth/logout"; - externalContext.redirect(logoutUrl); + // Quarkus gère la déconnexion Keycloak (end_session_endpoint) + redirection + // post-logout + String contextPath = externalContext.getRequestContextPath(); + externalContext.redirect(contextPath + "/auth/logout"); facesContext.responseComplete(); return null; @@ -449,4 +359,3 @@ public class UserSessionBean implements Serializable { } } } - diff --git a/src/main/resources/META-INF/faces-config.xml b/src/main/resources/META-INF/faces-config.xml index 6699f56..586c719 100644 --- a/src/main/resources/META-INF/faces-config.xml +++ b/src/main/resources/META-INF/faces-config.xml @@ -80,20 +80,6 @@ - - Page de visualisation d'un utilisateur spécifique - userViewPage - /pages/user-manager/users/view.xhtml - - - - - Navigation directe vers visualisation utilisateur - /pages/user-manager/users/view - /pages/user-manager/users/view.xhtml - - - Page d'édition utilisateur userEditPage @@ -190,23 +176,6 @@ - - - Page de démonstration complète Freya Extension - freyaShowcasePage - /pages/user-manager/freya-showcase.xhtml - - - - - Navigation directe vers Freya Showcase - /pages/user-manager/freya-showcase - /pages/user-manager/freya-showcase.xhtml - - - diff --git a/src/main/resources/META-INF/resources/index.xhtml b/src/main/resources/META-INF/resources/index.xhtml new file mode 100644 index 0000000..03bdbf0 --- /dev/null +++ b/src/main/resources/META-INF/resources/index.xhtml @@ -0,0 +1,58 @@ + + + + + + + Lions User Manager - Gestion des Utilisateurs Keycloak + + + + + + + + +
+
+
+ +

Lions User Manager

+

Gestion centralisée des utilisateurs Keycloak

+ +
+ + + + + + + + + + + +
+ +
+

Version 1.0.0

+

Module réutilisable pour l'écosystème LionsDev

+
+
+
+
+
+ + + diff --git a/src/main/resources/META-INF/resources/pages/user-manager/audit/logs.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/audit/logs.xhtml index 7c86c17..2f3e17c 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/audit/logs.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/audit/logs.xhtml @@ -1,316 +1,203 @@ - + - + Journal d'Audit - Lions User Manager
- +
-
-
-
- -
-

Journal d'Audit

-

Consultation des logs d'audit et statistiques système

+ + + + + + +
+ + + + + + +
-
- - -
-
+ +
- +
-
Statistiques d'Audit
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- -
-
-
-
-
Total Actions
-
#{auditConsultationBean.totalRecords}
-
-
- -
-
-
- - Actions enregistrées -
-
-
- - -
-
-
-
-
Actions Réussies
-
#{auditConsultationBean.successCount}
-
-
- -
-
-
- - - Succès - - Opérations validées -
-
-
- - -
-
-
-
-
Actions Échouées
-
#{auditConsultationBean.failureCount}
-
-
- -
-
-
- - - Échecs - - Opérations en erreur -
-
-
- - -
-
-
-
-
Taux de Réussite
-
- #{auditConsultationBean.totalRecords > 0 ? (auditConsultationBean.successCount * 100 / auditConsultationBean.totalRecords) : 0}% -
-
-
- -
-
-
- - Performance globale -
-
-
- - +
-
- -
Filtres de Recherche
-
- -
-
- +
Filtres de recherche
+
+
+ +
-
- +
+ + - +
-
- +
+ + - +
-
- +
+ +
-
- +
+ +
-
- +
+ +
-
- - +
+ +
- +
-
-
- -
Logs d'Audit
-
- -
- - +
Logs d'Audit
+ - - + + - -
- - #{log.typeAction} -
+ + #{log.typeAction} - +
-
- - #{log.acteurUsername != null and log.acteurUsername.length() > 1 ? log.acteurUsername.substring(0,2).toUpperCase() : 'XX'} - -
- #{log.acteurUsername} + + #{log.acteurUsername}
- +
- - #{log.ressourceType} + + #{log.ressourceType}
- +
- - #{log.dateAction} + + #{log.dateAction}
- - - #{not empty log.details ? log.details : '-'} - + + + #{log.details} + + + - + - - - #{not empty log.adresseIp ? log.adresseIp : '-'} - + + + #{log.adresseIp} + + + - + - - - - + + + +
@@ -318,103 +205,57 @@
- - + + -
- -
-
- Statut - -
-
- - -
- -

#{auditConsultationBean.selectedLog.typeAction}

-
- - -
- -
- -

#{auditConsultationBean.selectedLog.acteurUsername}

-
-
- - -
- -
- -

#{auditConsultationBean.selectedLog.ressourceType}

-
- ID: #{auditConsultationBean.selectedLog.ressourceId} -
- - -
- -
- -

#{auditConsultationBean.selectedLog.dateAction}

-
-
- - - + +
- -

#{auditConsultationBean.selectedLog.details}

+ Type d'action: +

#{auditConsultationBean.selectedLog.typeAction}

- - - -
- -

#{auditConsultationBean.selectedLog.adresseIp}

+ Acteur: +

#{auditConsultationBean.selectedLog.acteurUsername}

-
- - -
- -

#{auditConsultationBean.selectedLog.userAgent}

+ Ressource: +

#{auditConsultationBean.selectedLog.ressourceType} - + #{auditConsultationBean.selectedLog.ressourceId}

-
- - - -
- -

#{auditConsultationBean.selectedLog.messageErreur}

+
+ Date: +

#{auditConsultationBean.selectedLog.dateAction}

- -
- -
- -
+ +
+ Détails: +

#{auditConsultationBean.selectedLog.details}

+
+
+ +
+ Adresse IP: +

#{auditConsultationBean.selectedLog.adresseIp}

+
+
+ +
+ User Agent: +

#{auditConsultationBean.selectedLog.userAgent}

+
+
+ +
+ Message d'erreur: +

#{auditConsultationBean.selectedLog.messageErreur}

+
+
+
+
- + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/dashboard.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/dashboard.xhtml index d210e55..035efe9 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/dashboard.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/dashboard.xhtml @@ -1,406 +1,148 @@ - + Tableau de Bord - Lions User Manager - +
- +
-
-
-
- -
-

Tableau de Bord

-

Vue d'ensemble de la gestion des utilisateurs - Realm: #{dashboardBean.realmName}

-
-
- -
-
+ + + + + + + + + +
- +
-
Indicateurs Clés de Performance
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- -
-
- -
-
-
Total Utilisateurs
-
#{dashboardBean.totalUsersDisplay}
-
- - Dans le système -
-
-
- -
-
-
-
-
- - -
-
- -
-
-
Utilisateurs Actifs
-
#{dashboardBean.activeUsersDisplay}
-
- - Comptes activés -
-
-
- -
-
-
-
-
- - -
-
- -
-
-
Utilisateurs Inactifs
-
#{dashboardBean.inactiveUsersDisplay}
-
- - Comptes désactivés -
-
-
- -
-
-
-
-
- - -
-
- -
-
-
Taux de Succès
-
#{dashboardBean.successRate24hDisplay}
-
- - Dernières 24h -
-
-
- -
-
-
-
-
- - -
-
-
- -
Activité & Performance
-
- -
- -
-
-
Actions 24h
-
#{dashboardBean.actionsLast24hDisplay}
- -
-
- - -
-
-
Actions 7j
-
#{dashboardBean.actionsLast7dDisplay}
- -
-
- - -
-
-
Performance
-
#{dashboardBean.successRate24hDisplay}
- -
-
- - -
-
-
-
- - Actions réussies -
- #{dashboardBean.successfulActions24h} -
-
-
- - Actions échouées -
- #{dashboardBean.failedActions24h} -
-
-
-
-
-
- - -
-
-
- -
Actions Rapides
-
- + + + + + +
- +
- +
- +
- +
+
+
-
-
- -
-
Conseil
- Utilisez ces raccourcis pour accéder rapidement aux fonctionnalités principales -
+ + + + + + +
+
+ Version + 1.0.0 +
+
+ Realm Keycloak + lions-user-manager +
+
+ Statut + +
+
+ Application + Lions User Manager +
+
+ Environnement + Développement +
+
+ Base de données + Keycloak Admin API +
+
+ Framework + Quarkus, PrimeFaces Freya
-
-
- - - -
-
- -
Alertes de Sécurité
-
- -
- -
-
- -
#{dashboardBean.criticalActions24hDisplay}
-
Actions critiques
- Dernières 24h -
-
- - -
-
- -
#{dashboardBean.failedLogins24hDisplay}
-
Connexions échouées
- Dernières 24h -
-
- - -
-
- -
#{dashboardBean.usersAtRiskDisplay}
-
Utilisateurs à risque
- Nécessitent attention -
-
-
- -
-
- -
-
Recommandation
- Consultez le journal d'audit pour analyser les événements suspects -
-
-
-
-
- - -
-
-
- -
Ressources
-
- -
- -
-
-
-
-
- -
-
-
Rôles Realm
-
#{dashboardBean.totalRolesDisplay}
-
-
- -
-
-
- - -
-
-
-
- - Realm Keycloak -
-
- #{dashboardBean.realmName} - -
-
-
-
-
-
-
- - -
-
-
- -
Informations Système
-
- -
- -
-
-
- - Version Application -
- 1.0.0 -
-
- - -
-
-
- - Framework -
- Quarkus + PrimeFaces Freya -
-
- - -
-
-
- - Statut Système -
- -
-
-
-
-
+ +
- + - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/freya-showcase.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/freya-showcase.xhtml new file mode 100644 index 0000000..de9c587 --- /dev/null +++ b/src/main/resources/META-INF/resources/pages/user-manager/freya-showcase.xhtml @@ -0,0 +1,918 @@ + + + + Freya Extension Showcase - Lions User Manager + + + +
+ +
+
+
+
+ +
+

PrimeFaces Freya Extension Showcase

+

Démonstration complète des 46 composants personnalisés

+
+ + + +
+
+
+ +
+
+
+ + +
+

+ + Composants de Formulaire (Field Pattern) + +

+
+ + +
+
+
fr:fieldInput
+

Champ de saisie texte avec label et message de validation

+ + +
+
+ + +
+
+
fr:fieldPassword
+

Champ mot de passe avec validation de force

+ + +
+
+ + +
+
+
fr:fieldTextarea
+

Zone de texte multiligne pour descriptions

+ + +
+
+ + +
+
+
fr:fieldNumber
+

Champ numérique avec contrôles + / -

+ + +
+
+ + +
+
+
fr:fieldCalendar
+

Sélecteur de date avec calendrier popup

+ + +
+
+ + +
+
+
fr:fieldSelect
+

Liste déroulante simple sélection

+ + + + + + + + +
+
+ + +
+
+
fr:fieldMultiSelect
+

Sélection multiple avec chips

+ + + + + + + + +
+
+ + +
+
+
fr:fieldCheckbox
+

Case à cocher pour valeurs booléennes

+ + +
+
+ + +
+
+
fr:fieldRadio
+

Boutons radio pour choix exclusif

+ + + + + + +
+
+ + +
+
+
fr:fieldSwitch
+

Interrupteur on/off moderne

+ + +
+
+ + +
+
+
fr:fieldToggle
+

Bouton toggle avec états on/off

+ + +
+
+ + +
+
+
fr:fieldSlider
+

Curseur pour sélection de valeur numérique

+ + +

Valeur sélectionnée: #{demoBean.user.volume != null ? demoBean.user.volume : 50}%

+
+
+ + +
+
+
fr:fieldRating
+

Évaluation par étoiles

+ + +
+
+ + +
+
+
fr:fieldChips
+

Saisie de tags/mots-clés multiples

+ + +
+
+ + +
+
+
fr:fieldColor
+

Sélecteur de couleur avec palette

+ + +
+
+ + +
+
+
fr:fieldEditor
+

Éditeur de texte riche WYSIWYG

+ + +
+
+ + +
+
+
fr:fieldMask
+

Champ avec masque de saisie (téléphone, etc.)

+ + +
+
+ + +
+
+
fr:fieldAutoComplete
+

Saisie avec suggestions automatiques

+ + +
+
+ + +
+
+
fr:fieldSpinner
+

Compteur numérique avec incréments

+ + +
+
+ + +
+
+
fr:fieldFileUpload
+

Upload de fichiers avec contraintes

+ + +

Formats acceptés: PDF, DOC, DOCX (max 3 fichiers)

+
+
+ + +
+

+ + Composants d'Action + +

+
+ + +
+
+
fr:button
+

Bouton de navigation simple (sans Ajax)

+ +
+ + + + + + + +
+
+
+ + +
+
+
fr:commandButton
+

Bouton avec action Ajax

+ +
+ + + +
+
+
+ + +
+
+
fr:linkButton
+

Bouton sous forme de lien

+ +
+ + + +
+
+
+ + +
+
+
fr:splitButton
+

Bouton avec menu déroulant d'actions

+ + + + + + + +
+
+ + +
+
+
fr:actionDialog
+

Dialogue modal pour confirmation d'action

+ + + + +
+
+ + +
+

+ + Composants de Layout + +

+
+ + +
+ +

+ Ceci est le contenu de la carte. Les cartes sont utilisées pour regrouper + des informations connexes dans un conteneur visuellement distinct. +

+ + +
+ + +
+
+
+
+ + +
+ +

+ Panel pliable/dépliable pour organiser le contenu en sections. + Cliquez sur l'icône pour replier/déplier. +

+
+
+ + +
+
+
fr:divider
+

Séparateur visuel horizontal ou vertical

+ +
+

Contenu avant le divider

+ +

Contenu après le divider

+
+ + + Divider avec texte aligné à gauche + + + + + +
+
+ + +
+
+
fr:spacer
+

Espace vide pour ajuster la mise en page

+ +
+ Élément gauche + + Élément droite +
+
+
+ + +
+

+ + Composants de Navigation + +

+
+ + +
+
+
fr:breadcrumb
+

Fil d'Ariane pour navigation hiérarchique

+ + + + + + +
+
+ + +
+
+
fr:steps
+

Indicateur de progression par étapes

+ + + + + + +
+
+ + +
+ + +

+ Contenu du premier onglet. Les onglets permettent d'organiser le contenu en sections + accessibles via des onglets cliquables. +

+
+ +

+ Contenu du deuxième onglet avec informations différentes. +

+
+ +

+ Troisième onglet pour démonstration complète. +

+
+
+
+ + +
+

+ + Composants de Données + +

+
+ + +
+
+
fr:dataTable
+

Tableau de données avec tri, filtrage et pagination

+ + + + + + + + + + + + +
+
+ + +
+
+
fr:dataView
+

Affichage de données en grille/liste avec templates

+ + + +
+
+ + #{user.nom} +
+

#{user.email}

+
+
+
+
+
+ + +
+
+
fr:tree
+

Arborescence hiérarchique navigable

+ + + + + + +
+
+ + +
+
+
fr:treeTable
+

Tableau arborescent avec colonnes

+ + + + + + + + + +
+
+ + +
+
+
fr:inplace
+

Édition en ligne activable au clic

+ + + + +
+
+ + +
+

+ + Composants de Feedback + +

+
+ + +
+
+
fr:message
+

Message de validation pour champ spécifique

+ + + +
+
+ + +
+
+
fr:growl
+

Notifications toast en coin d'écran

+ + + + +
+
+ + +
+
+
fr:progressBar
+

Barre de progression pour opérations longues

+ + +
+ + +
+
+
+ + +
+

+ + Composants Utilitaires + +

+
+ + +
+
+
fr:avatar
+

Avatar utilisateur avec image ou initiales

+ +
+ + + + +
+
+
+ + +
+
+
fr:badge
+

Badge de notification avec compteur

+ +
+ + + + + + + + + +
+
+
+ + +
+
+
fr:tag
+

Tags colorés pour statuts et catégories

+ +
+ + + + + + + +
+
+
+ + +
+

+ + Composants Avancés + +

+
+ + +
+
+
fr:chart
+

Graphique avec Chart.js (bar, line, pie, etc.)

+ + + + #{demoBean.chartData} + + +
+
+ + +
+
+
fr:formDialog
+

Dialogue modal avec formulaire intégré

+ + + + + + + +
+
+ + +
+
+
fr:themeSelector
+

Sélecteur de thème Freya (16 variantes)

+ + +

+ + Ce composant permet de changer dynamiquement le thème de l'application parmi + les 16 variantes Freya (8 couleurs × 2 modes dark/light) +

+
+
+ + +
+
+
+ +

Intégration Complète Réussie

+

+ Les 46 composants PrimeFaces Freya Extension sont maintenant disponibles dans Lions User Manager +

+
+ + + + + + + + +
+
+
+
+
+
+
+ +
diff --git a/src/main/resources/META-INF/resources/pages/user-manager/roles/assign.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/roles/assign.xhtml new file mode 100644 index 0000000..fb148e0 --- /dev/null +++ b/src/main/resources/META-INF/resources/pages/user-manager/roles/assign.xhtml @@ -0,0 +1,14 @@ + + + + + + + Redirecting... + + + Redirecting to user list... + + + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/roles/list.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/roles/list.xhtml index 8f50da6..8f2c285 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/roles/list.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/roles/list.xhtml @@ -4,447 +4,163 @@ xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" - xmlns:fr="http://primefaces.org/freya" + xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" template="/templates/main-template.xhtml"> Gestion des Rôles - Lions User Manager -
- -
-
-
-
- -
-

Gestion des Rôles

-

Gestion des rôles Realm et Client Keycloak

-
-
-
- - -
+ + + + + + + +
+ + + + + + + + + + + + + + + +
-
-
+ + + - -
-
-
- -
-

- - Filtres -

+ +
+ + + + + + + + - -
- -
- - - - - -
+ + + + + + - -
- - - - - -
- - -
- - - - -
-
-
-
- - -
-

- - Statistiques (φ = 1.618) -

- - -
- -
-
-
- -
-
#{roleGestionBean.realmRoles.size()}
-
Rôles Realm
-
-
- - -
-
-
- -
-
#{roleGestionBean.clientRoles.size()}
-
Rôles Client
-
-
- - -
-
-
- -
-
#{roleGestionBean.allRoles.size()}
-
Total Rôles
-
-
- - -
-
-
- -
-
#{roleGestionBean.realmName}
-
Realm Actif
-
-
-
-
-
-
-
-
- - -
-
- -
-

- - Rôles Realm -

- -
- -
- -
-
-
-
-

- - #{role.name} -

-

- - -

-
-
- - - -
-
- -
- - - REALM - - - - COMPOSITE - -
- -
- - ID: #{role.id != null ? role.id : 'N/A'} -
-
-
-
- - -
-
- -

Aucun rôle Realm trouvé

- Sélectionnez un realm ou créez un nouveau rôle -
-
-
-
-
-
- - -
-
- -
-

- - Rôles Client -

- -
- -
- -
-
-
-
-

- - #{role.name} -

-

- - -

-
-
- - - -
-
- -
- - - CLIENT - - - - COMPOSITE - - - #{role.clientName} - -
- -
- - ID: #{role.id != null ? role.id : 'N/A'} -
-
-
-
- - -
-
- -

Aucun rôle Client trouvé

- Sélectionnez un client ou créez un nouveau rôle -
-
-
-
-
-
+ + + + + + +
- - -
-
- - - - -
+ +
+ + +
+ +
+ + + + +
+
+ +
+

Aucun rôle Realm trouvé

+
+
+
+
+
+
-
- -
-
+ +
+ + +
+ +
+ + + + +
+
+ +
+

Aucun rôle Client trouvé

+
+
+
+
+
+
- - - -
+ + + + + + + + + + + + + + - - -
-
- - - - -
- -
- - - - -
- -
- -
-
- - - - -
- - - - - - - + + + + + + + + + + + + + + + diff --git a/src/main/resources/META-INF/resources/pages/user-manager/settings.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/settings.xhtml index eefd7aa..109f651 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/settings.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/settings.xhtml @@ -4,7 +4,6 @@ xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" - xmlns:fr="http://primefaces.org/freya" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" template="/templates/main-template.xhtml"> @@ -25,43 +24,31 @@
Informations du compte
-
-
- -
+ + + -
- -
+ + -
- -
+ + -
- -
-
+ + +
@@ -72,34 +59,35 @@
Préférences
- - - - - - - - - - - - - - - - +
+ Thème des composants + + + + +
+
+ Mode sombre + + + + + +
+
+ Style d'input + + + + + +
@@ -109,26 +97,29 @@
Actions
-
+
- + - + - +
diff --git a/src/main/resources/META-INF/resources/pages/user-manager/sync/dashboard.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/sync/dashboard.xhtml index 1283dbe..d0a8be7 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/sync/dashboard.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/sync/dashboard.xhtml @@ -1,50 +1,99 @@ - + Synchronisation Keycloak - Lions User Manager - - - - - - + + - -
-
-
-
État de Keycloak
- - -
+ +
+ + + + + + + +
-
-
-
Actions de Synchronisation
-
- - - - - - - - - - + +
+ +
+
+
État de Keycloak
+
+
+ +
+
+ + #{syncDashboardBean.keycloakStatusLabel eq 'UP' ? 'En Ligne' : 'Hors Ligne'} + + Statut du service +
+ + + +
+ + + +
+
+ Message: + #{syncDashboardBean.keycloakStatusMessage} +
+
+ Version: + #{syncDashboardBean.keycloakVersion} +
+
+
+
+ + +
+
+
Actions de Synchronisation
+

Lancez la synchronisation des données depuis Keycloak vers la base + locale.

+ +
+
+
+ + Utilisateurs +
+ +
+ +
+
+ + Rôles +
+ +
+
-
+ - - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/users/create.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/users/create.xhtml index 1ef1a19..fcfd70e 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/users/create.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/users/create.xhtml @@ -1,13 +1,9 @@ - + - + Nouvel Utilisateur - Lions User Manager @@ -22,24 +18,13 @@

Nouvel Utilisateur

-

Créer un nouvel utilisateur dans le realm Keycloak

+

Créer un nouvel utilisateur dans Keycloak

-
- - -
+ + + Retour à la liste +
@@ -47,261 +32,142 @@ - - +
- -
+
+

+ + Informations de l'Utilisateur +

- -
-
- -
-
-
- -
Informations de Base
-
+
+ +
+
+

+ + Informations de Base +

-
-
- - - +
+ + + + + Identifiant unique de connexion
-
- - - +
+ + + +
-
- - - +
+ + + +
-
- - - +
+ + + +
-
- -
-
-
- -
Sécurité
-
+ +
+ +
+

+ + Mot de Passe +

-
-
- - - - +
+ + + + + Au moins 8 caractères
-
- - - - -
-
- - -
-
- -
-
Recommandations de sécurité
- - Utilisez un mot de passe fort contenant des majuscules, minuscules, chiffres et caractères spéciaux. - L'utilisateur pourra le modifier lors de sa première connexion. - -
-
-
-
-
- - -
-
-
- -
Configuration
-
- -
- -
- - - -
- - -
-
-
-
-
-
- -
-
-
- -
Aperçu
-
+ +
+

+ + Configuration +

- -
-
- -
-
+ +
+ + + + +
- -
- -
- Nom d'utilisateur -
- -
-
+ +
+ +
+ + + +
- -
- Nom complet -
- -
-
- - -
- Email -
- -
-
- - -
- Statut -
- - -
-
- - -
- Realm -
- - #{userCreationBean.realmName} + +
+ + + +
+
@@ -313,43 +179,47 @@ ================================================================ -->
-
-
- - +

+ + Actions +

- - - - +
+ + + - - -
+ + + + - -
- - * Champs obligatoires -
+ + + + + +
+ + + +
+ + + + +
@@ -358,101 +228,55 @@ - - - + + + - -
- -
-
- -
Informations Requises
-
-
-
    -
  • - Nom d'utilisateur : Identifiant unique de 3 à 50 caractères. - Ex: jdupont, marie.martin -
  • -
  • - Email : Adresse email valide et unique. - Ex: utilisateur@example.com -
  • -
  • - Prénom et Nom : Identification complète de l'utilisateur. -
  • -
  • - Mot de passe : Au moins 8 caractères requis. -
  • -
-
-
+ +
+
+

+ + Informations Requises +

+
    +
  • Nom d'utilisateur : Identifiant unique (3-50 caractères)
  • +
  • Email : Adresse email valide
  • +
  • Mot de passe : Au moins 8 caractères
  • +
- -
-
- -
Recommandations de Sécurité
-
-
-
    -
  • Utilisez un mot de passe fort avec majuscules, minuscules, chiffres et symboles
  • -
  • Évitez les mots de passe trop simples ou courants
  • -
  • Le mot de passe sera hashé et sécurisé par Keycloak
  • -
  • L'utilisateur pourra modifier son mot de passe après connexion
  • -
-
-
+

+ + Sécurité +

+
    +
  • Le mot de passe doit contenir au moins 8 caractères
  • +
  • Utilisez une combinaison de lettres, chiffres et caractères spéciaux
  • +
  • L'utilisateur pourra modifier son mot de passe après la première connexion
  • +
- -
-
- -
Options de Configuration
-
-
-
    -
  • - Compte activé : Si coché, l'utilisateur peut se connecter immédiatement. -
  • -
  • - Email vérifié : Si coché, l'email est considéré comme vérifié (pas de vérification requise). -
  • -
  • - Realm : lions-user-manager est le realm par défaut pour la gestion des utilisateurs. -
  • -
-
+

+ + Configuration +

+
    +
  • Compte activé : L'utilisateur peut se connecter immédiatement
  • +
  • Email vérifié : L'email est considéré comme vérifié
  • +
  • Realm : Espace d'administration Keycloak
  • +
-
- -
+
- + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/users/edit.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/users/edit.xhtml index 0c16c29..c7fd547 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/users/edit.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/users/edit.xhtml @@ -1,314 +1,49 @@ - + + - + Modifier Utilisateur - Lions User Manager -
- -
-
-
-
- -
-

Modifier Utilisateur

-

Modifier les informations d'un utilisateur existant dans Keycloak

-
-
-
- - - - - Voir le profil - - - - Retour - -
-
-
-
+ + + + + + - - - -
- -
+
+ + + + + + + + + + + - - -
-
- -
-
-
- -
Informations de Base
-
- -
- -
- - - -
- - -
- - - - -
- - -
- - - - -
- - -
- - - - -
- - -
- -
-
-
-
- - -
-
-
- -
Configuration
-
- -
- -
- -
- - -
- -
-
- - - - - -
-
-
-
-
-
-
-
- - -
-
-
- -
Aperçu (Temps réel)
-
- - - - -
-
- -
-
- - -
- -
- Nom d'utilisateur -
- -
-
- - -
- Nom complet -
- -
-
- - -
- Email -
- -
-
- - -
- Statut -
- - -
-
- - -
- Realm -
- - #{userProfilBean.realmName} -
-
-
- -
-
-
- - -
-
-
-
- - - - - - - - -
- - -
- - * Champs obligatoires -
-
-
-
-
- - - -
-
-
- -

Utilisateur non trouvé

-

L'utilisateur demandé n'existe pas ou n'a pas pu être chargé.

- - - Retour à la liste - -
-
-
-
- + + + + + + + + + +
- - - - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/users/list.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/users/list.xhtml index 2eaabf3..6ff16d0 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/users/list.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/users/list.xhtml @@ -1,13 +1,9 @@ - + - + Liste des Utilisateurs - Lions User Manager @@ -23,37 +19,15 @@

Gestion des Utilisateurs

-

Gestion centralisée des utilisateurs Keycloak - Recherche, création, modification et suppression

+

Gestion centralisée des utilisateurs Keycloak - Recherche, + création, modification et suppression

- - - - + +
@@ -75,7 +49,7 @@
#{userListBean.totalRecords}
+ style="width: 2.5rem; height: 2.5rem">
@@ -95,7 +69,7 @@
#{userListBean.activeUsersCount}
+ style="width: 2.5rem; height: 2.5rem">
@@ -106,10 +80,8 @@ Taux d'activation
- +
@@ -122,7 +94,7 @@
#{userListBean.disabledUsersCount}
+ style="width: 2.5rem; height: 2.5rem">
@@ -133,10 +105,8 @@ Taux de désactivation
- +
@@ -146,10 +116,11 @@
Realm Actuel
-
#{userListBean.realmName}
+
+ #{userListBean.realmName}
+ style="width: 2.5rem; height: 2.5rem">
@@ -164,422 +135,124 @@ SECTION RECHERCHE ET FILTRES ================================================================ -->
- - - - - - +
+
+ +
Recherche et Filtres
+
- - - + + + +
- - - - + + + + + +
- + + - - + +
-
- +
+
- +
+
+ + + + + + + + + + + + +
+ +
-
-
- -
Liste des Utilisateurs
-
- +
+ +
Actions Rapides
- - - - - - - - -
-
- - #{user.prenom != null ? user.prenom.substring(0,1).toUpperCase() : 'U'}#{user.nom != null ? user.nom.substring(0,1).toUpperCase() : 'U'} - -
-
- #{user.username} - #{user.prenom} #{user.nom} -
-
-
- - - -
- - #{user.email} - - - -
-
- - - - - - - - -
- - - - - - - - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- +
+
+ +
+
+ +
+
+ +
+
+ +
+
- - - - -
-
- -
-
Format du fichier CSV requis:
-
    -
  • En-tête: username,prenom,nom,email
  • -
  • Encodage: UTF-8
  • -
  • Séparateur: virgule (,)
  • -
-
-
-
- - -
-
Télécharger le template CSV:
- - - Utilisez ce template pour préparer votre fichier d'import - -
- - - - -
-
Sélectionner le fichier CSV:
- -
- -
-
- - - Astuce: Exportez d'abord vos utilisateurs existants pour voir le format attendu - + + +
+

+ Importez des utilisateurs depuis un fichier CSV ou JSON. +

+ +
+ +
- - - - - - - -
-
Résumé de l'import:
-
-
-
-
Total lignes
-
#{userListBean.lastImportResult.totalLines}
-
-
-
-
-
Succès
-
#{userListBean.lastImportResult.successCount}
-
-
-
-
-
Erreurs
-
#{userListBean.lastImportResult.errorCount}
-
-
-
-
- - - - - Détails des Erreurs - - - - - - - - - - - - - - #{error.field != null ? error.field : '-'} - - - -
- #{error.message} - - #{error.lineContent} - -
-
-
-
- - - -
- -
Import réussi!
-

- Tous les utilisateurs ont été importés avec succès. -

-
-
- - -
- -
-
-
-
- - - - - - - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/user-manager/users/profile.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/users/profile.xhtml index 6cf4f46..ee6b1df 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/users/profile.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/users/profile.xhtml @@ -4,7 +4,6 @@ xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui" - xmlns:fr="http://primefaces.org/freya" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" template="/templates/main-template.xhtml"> @@ -121,7 +120,7 @@
- +
@@ -129,9 +128,10 @@
- + +
@@ -149,7 +149,7 @@
- +
@@ -198,7 +198,7 @@
- +
@@ -333,29 +333,26 @@ Gestion du Profil
- + - + - + - + - + - +
@@ -368,33 +365,28 @@ Sessions et Sécurité
- + - + - + - + - + - +
@@ -405,19 +397,16 @@
- - - + + diff --git a/src/main/resources/META-INF/resources/pages/user-manager/users/view.xhtml b/src/main/resources/META-INF/resources/pages/user-manager/users/view.xhtml index 601c42a..5ab9438 100644 --- a/src/main/resources/META-INF/resources/pages/user-manager/users/view.xhtml +++ b/src/main/resources/META-INF/resources/pages/user-manager/users/view.xhtml @@ -1,19 +1,15 @@ - + - + Profil Utilisateur - Lions User Manager @@ -40,135 +36,31 @@
-
-
- -
- -
-
- -
- #{userProfilBean.user.prenom != null ? userProfilBean.user.prenom.substring(0,1).toUpperCase() : 'U'}#{userProfilBean.user.nom != null ? userProfilBean.user.nom.substring(0,1).toUpperCase() : 'U'} -
+ +
+
+ + + + + + + + + + + + + +
+
+
- -

#{userProfilBean.user.prenom} #{userProfilBean.user.nom}

- - -

- - #{userProfilBean.user.email} -

- - -
- -
- - -
- - -
-
-
- - -
-
- -
-

- - Informations Personnelles -

- -
- -

#{userProfilBean.user.username}

-
- -
- -

#{userProfilBean.user.prenom} #{userProfilBean.user.nom}

-
- -
- -
-

#{userProfilBean.user.email}

- -
-
- -
- -

#{userProfilBean.user.prenom}

-
- -
- -

#{userProfilBean.user.nom}

-
- -
- -

#{userProfilBean.user.telephone}

-
-
- - -
-

- - Rôles et Permissions -

- -
- -
- - - - -
-
- -
- -
- -
-
- -
- -

#{userProfilBean.realmName}

-
-
-
-
-
-
- - + +
+

Utilisateur non trouvé

@@ -178,55 +70,10 @@ Retour à la liste
- +
-
- - -
-
-

- - Actions -

- - -
-
- - - - -
-
- - - - -
-
- -
-
-
-
-
+
- - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/templates/components/audit/audit-log-row.xhtml b/src/main/resources/META-INF/resources/templates/components/audit/audit-log-row.xhtml index 403ae5b..d722251 100644 --- a/src/main/resources/META-INF/resources/templates/components/audit/audit-log-row.xhtml +++ b/src/main/resources/META-INF/resources/templates/components/audit/audit-log-row.xhtml @@ -1,21 +1,19 @@ - + - + - - - - - -
- + + + + + + + +
+ -
- +
+
- +
-
+
#{auditLog.typeAction} - +
- -
+ +
- #{auditLog.acteurUsername} + + + #{auditLog.acteurUsername} + - #{auditLog.ressourceType} + + + #{auditLog.ressourceType} + - #{auditLog.dateAction} + + + #{auditLog.dateAction} + + + + + + #{auditLog.realmName} +
- - + + -
- -
Ressource ID: #{auditLog.ressourceId}
-
- -
Détails: #{auditLog.details}
-
- -
IP: #{auditLog.adresseIp}
-
- -
User Agent: #{auditLog.userAgent}
-
- -
Erreur: #{auditLog.messageErreur}
-
+
+
+ +
+ Ressource ID: + #{auditLog.ressourceId} +
+
+ +
+ Adresse IP: + #{auditLog.adresseIp} +
+
+ +
+ Détails: + #{auditLog.details} +
+
+ +
+ User Agent: + + #{auditLog.userAgent} + +
+
+ +
+ Erreur: + #{auditLog.messageErreur} +
+
+
- - + + -
- +
+
- - + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/templates/components/audit/audit-stats-card.xhtml b/src/main/resources/META-INF/resources/templates/components/audit/audit-stats-card.xhtml index f964b99..3a57e37 100644 --- a/src/main/resources/META-INF/resources/templates/components/audit/audit-stats-card.xhtml +++ b/src/main/resources/META-INF/resources/templates/components/audit/audit-stats-card.xhtml @@ -1,28 +1,31 @@ - + - - - - -
- - - -
-
- #{title} -
- -
-
- -
#{value}
- - -
#{subtitle}
-
- - -
- - - #{trend >= 0 ? '+' : ''}#{trend}% - - - #{trendLabel} - -
-
-
-
-
- - -
-
- #{title} -
- -
-
- -
#{value}
- - -
#{subtitle}
-
- - -
- - - #{trend >= 0 ? '+' : ''}#{trend}% - - - #{trendLabel} - -
-
-
-
-
-
- -
+ + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml b/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml index 50c31a4..d7765a1 100644 --- a/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml +++ b/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml @@ -1,9 +1,6 @@ - + -