package dev.lions.unionflow.client.view; import dev.lions.unionflow.server.api.dto.user.request.CreateUserRequest; import dev.lions.unionflow.server.api.dto.user.request.UpdateUserRequest; import dev.lions.unionflow.server.api.dto.user.response.UserResponse; import dev.lions.unionflow.server.api.dto.base.PageResponse; import dev.lions.unionflow.server.api.dto.common.PagedResponse; import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse; import dev.lions.unionflow.client.service.AdminUserService; import dev.lions.unionflow.client.service.AssociationService; import jakarta.enterprise.context.SessionScoped; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.annotation.PostConstruct; import org.eclipse.microprofile.rest.client.inject.RestClient; import java.io.Serializable; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import org.jboss.logging.Logger; /** * Bean de gestion des utilisateurs Keycloak (liste, filtres, statistiques). * Appelle l'API Unionflow /api/admin/users (réservée SUPER_ADMIN). */ @Named("utilisateursBean") @SessionScoped public class UtilisateursBean implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(UtilisateursBean.class); @Inject @RestClient private AssociationService associationService; @Inject @RestClient private AdminUserService adminUserService; private List tousLesUtilisateurs; private List utilisateursFiltres; private List utilisateursSelectionnes; private List organisationsDisponibles; private Utilisateur utilisateurSelectionne; private NouvelUtilisateur nouvelUtilisateur; private Filtres filtres; private StatistiquesUtilisateurs statistiques; @PostConstruct public void init() { initializeFiltres(); initializeOrganisations(); initializeUtilisateurs(); initializeStatistiques(); initializeNouvelUtilisateur(); appliquerFiltres(); } private void initializeFiltres() { filtres = new Filtres(); utilisateursSelectionnes = new ArrayList<>(); } private void initializeStatistiques() { statistiques = new StatistiquesUtilisateurs(); statistiques.setTotalUtilisateurs(tousLesUtilisateurs != null ? tousLesUtilisateurs.size() : 0); statistiques.setUtilisateursConnectes(0); statistiques .setAdministrateurs(tousLesUtilisateurs != null ? (int) tousLesUtilisateurs.stream() .filter(u -> "ADMIN".equals(u.getRole()) || "SUPER_ADMIN".equals(u.getRole())).count() : 0); statistiques.setUtilisateursDesactives(tousLesUtilisateurs != null ? (int) tousLesUtilisateurs.stream().filter(u -> "INACTIF".equals(u.getStatut())).count() : 0); } private void initializeOrganisations() { organisationsDisponibles = new ArrayList<>(); try { PagedResponse response = associationService.listerToutes(0, 1000); List associations = (response != null && response.getData() != null) ? response.getData() : new ArrayList<>(); for (OrganisationResponse assoc : associations) { Organisation org = new Organisation(); org.setId(assoc.getId()); org.setNom(assoc.getNom()); organisationsDisponibles.add(org); } } catch (Exception e) { LOG.errorf(e, "Erreur lors du chargement des organisations"); } } private void initializeUtilisateurs() { tousLesUtilisateurs = new ArrayList<>(); try { PageResponse result = adminUserService.lister(0, 1000, null); if (result != null && result.getContenu() != null) { for (UserResponse dto : result.getContenu()) { Utilisateur u = mapToUtilisateur(dto); tousLesUtilisateurs.add(u); } } LOG.infof("Utilisateurs chargés: %d", tousLesUtilisateurs.size()); } catch (Exception e) { LOG.warnf(e, "Impossible de charger les utilisateurs (API admin): %s", e.getMessage()); } } private Utilisateur mapToUtilisateur(UserResponse dto) { Utilisateur u = new Utilisateur(); u.setId(dto.getId()); u.setPrenom(dto.getPrenom()); u.setNom(dto.getNom()); u.setEmail(dto.getEmail()); u.setRole(dto.getPrimaryRole()); u.setStatut(Boolean.TRUE.equals(dto.getEnabled()) ? "ACTIF" : "INACTIF"); u.setDateCreation(dto.getDateCreation()); u.setDerniereConnexion(dto.getDerniereConnexion()); return u; } private void initializeNouvelUtilisateur() { nouvelUtilisateur = new NouvelUtilisateur(); nouvelUtilisateur.setRole("USER"); nouvelUtilisateur.setEnvoyerEmail(true); } private void appliquerFiltres() { utilisateursFiltres = tousLesUtilisateurs.stream() .filter(this::appliquerFiltre) .collect(Collectors.toList()); } private boolean appliquerFiltre(Utilisateur utilisateur) { if (filtres.getRecherche() != null && !filtres.getRecherche().trim().isEmpty()) { String recherche = filtres.getRecherche().toLowerCase(); if (!utilisateur.getNomComplet().toLowerCase().contains(recherche) && !utilisateur.getEmail().toLowerCase().contains(recherche)) { return false; } } if (filtres.getRole() != null && !filtres.getRole().trim().isEmpty()) { if (!utilisateur.getRole().equals(filtres.getRole())) { return false; } } if (filtres.getStatut() != null && !filtres.getStatut().trim().isEmpty()) { if (!utilisateur.getStatut().equals(filtres.getStatut())) { return false; } } if (filtres.getOrganisation() != null && !filtres.getOrganisation().toString().trim().isEmpty()) { if (!utilisateur.getOrganisationId().equals(filtres.getOrganisation())) { return false; } } return true; } // Actions public void rechercher() { appliquerFiltres(); } public void reinitialiserFiltres() { filtres = new Filtres(); appliquerFiltres(); } public void creerUtilisateur() { if (nouvelUtilisateur == null || nouvelUtilisateur.getEmail() == null || nouvelUtilisateur.getEmail().isBlank()) { LOG.warn("Création utilisateur: email obligatoire"); return; } try { CreateUserRequest request = CreateUserRequest.builder() .prenom(nouvelUtilisateur.getPrenom()) .nom(nouvelUtilisateur.getNom()) .email(nouvelUtilisateur.getEmail()) .username(nouvelUtilisateur.getEmail() != null ? nouvelUtilisateur.getEmail().trim().toLowerCase() : null) .password(nouvelUtilisateur.getMotDePasse()) .enabled(true) .emailVerified(false) .realmRoles(nouvelUtilisateur.getRole() != null ? Collections.singletonList(nouvelUtilisateur.getRole()) : Collections.singletonList("USER")) .build(); adminUserService.creer(request); LOG.infof("Utilisateur créé: %s", request.email()); initializeUtilisateurs(); initializeStatistiques(); appliquerFiltres(); initializeNouvelUtilisateur(); } catch (Exception e) { LOG.errorf(e, "Erreur création utilisateur: %s", e.getMessage()); } } public void activerUtilisateur(Utilisateur utilisateur) { if (utilisateur == null || utilisateur.getId() == null) return; try { UpdateUserRequest request = UpdateUserRequest.builder() .enabled(true) .build(); adminUserService.mettreAJour(utilisateur.getId().toString(), request); LOG.infof("Utilisateur activé: %s", utilisateur.getEmail()); initializeUtilisateurs(); initializeStatistiques(); appliquerFiltres(); } catch (Exception e) { LOG.errorf(e, "Erreur activation utilisateur: %s", e.getMessage()); } } public void desactiverUtilisateur(Utilisateur utilisateur) { if (utilisateur == null || utilisateur.getId() == null) return; try { UpdateUserRequest request = UpdateUserRequest.builder() .enabled(false) .build(); adminUserService.mettreAJour(utilisateur.getId().toString(), request); LOG.infof("Utilisateur désactivé: %s", utilisateur.getEmail()); initializeUtilisateurs(); initializeStatistiques(); appliquerFiltres(); } catch (Exception e) { LOG.errorf(e, "Erreur désactivation utilisateur: %s", e.getMessage()); } } public void exporterUtilisateurs() { // Export côté client à partir des données déjà chargées (utilisateursFiltres) LOG.info("Export utilisateurs (données courantes)"); } // Getters et Setters public List getTousLesUtilisateurs() { return tousLesUtilisateurs; } public void setTousLesUtilisateurs(List tousLesUtilisateurs) { this.tousLesUtilisateurs = tousLesUtilisateurs; } public List getUtilisateursFiltres() { return utilisateursFiltres; } public void setUtilisateursFiltres(List utilisateursFiltres) { this.utilisateursFiltres = utilisateursFiltres; } public List getUtilisateursSelectionnes() { return utilisateursSelectionnes; } public void setUtilisateursSelectionnes(List utilisateursSelectionnes) { this.utilisateursSelectionnes = utilisateursSelectionnes; } public List getOrganisationsDisponibles() { return organisationsDisponibles; } public void setOrganisationsDisponibles(List organisationsDisponibles) { this.organisationsDisponibles = organisationsDisponibles; } public Utilisateur getUtilisateurSelectionne() { return utilisateurSelectionne; } public void setUtilisateurSelectionne(Utilisateur utilisateurSelectionne) { this.utilisateurSelectionne = utilisateurSelectionne; } public NouvelUtilisateur getNouvelUtilisateur() { return nouvelUtilisateur; } public void setNouvelUtilisateur(NouvelUtilisateur nouvelUtilisateur) { this.nouvelUtilisateur = nouvelUtilisateur; } public Filtres getFiltres() { return filtres; } public void setFiltres(Filtres filtres) { this.filtres = filtres; } public StatistiquesUtilisateurs getStatistiques() { return statistiques; } public void setStatistiques(StatistiquesUtilisateurs statistiques) { this.statistiques = statistiques; } // Classes internes public static class Utilisateur { private UUID id; private String nom; private String prenom; private String email; private String telephone; private String role; private String statut; private UUID organisationId; private LocalDateTime dateCreation; private LocalDateTime derniereConnexion; // Getters et setters public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; } public String getPrenom() { return prenom; } public void setPrenom(String prenom) { this.prenom = prenom; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getStatut() { return statut; } public void setStatut(String statut) { this.statut = statut; } public UUID getOrganisationId() { return organisationId; } public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; } public LocalDateTime getDateCreation() { return dateCreation; } public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; } public LocalDateTime getDerniereConnexion() { return derniereConnexion; } public void setDerniereConnexion(LocalDateTime derniereConnexion) { this.derniereConnexion = derniereConnexion; } // Propriétés dérivées public String getNomComplet() { if (prenom != null && nom != null) return prenom + " " + nom; if (prenom != null) return prenom; if (nom != null) return nom; return email != null ? email : "—"; } public String getRoleLibelle() { return switch (role) { case "USER" -> "Utilisateur"; case "GESTIONNAIRE" -> "Gestionnaire"; case "ADMIN" -> "Administrateur"; case "SUPER_ADMIN" -> "Super Admin"; default -> role; }; } public String getRoleSeverity() { return switch (role) { case "USER" -> "info"; case "GESTIONNAIRE" -> "primary"; case "ADMIN" -> "warning"; case "SUPER_ADMIN" -> "danger"; default -> "secondary"; }; } public String getStatutLibelle() { return switch (statut) { case "ACTIF" -> "Actif"; case "INACTIF" -> "Inactif"; case "SUSPENDU" -> "Suspendu"; case "ATTENTE" -> "En attente"; default -> statut; }; } public String getStatutSeverity() { return switch (statut) { case "ACTIF" -> "success"; case "INACTIF" -> "secondary"; case "SUSPENDU" -> "danger"; case "ATTENTE" -> "warning"; default -> "secondary"; }; } public String getOrganisationNom() { // Simulation - en réalité, on ferait un lookup dans la base if (organisationId == null) return "Non définie"; String orgIdStr = organisationId.toString(); if (orgIdStr.contains("000000000100")) return "Direction Générale"; if (orgIdStr.contains("000000000200")) return "Services Financiers"; if (orgIdStr.contains("000000000300")) return "Ressources Humaines"; if (orgIdStr.contains("000000000400")) return "Communication"; return "Non définie"; } public String getDateCreationFormatee() { if (dateCreation == null) return ""; return dateCreation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")); } public String getDerniereConnexionFormatee() { if (derniereConnexion == null) return "Jamais"; return derniereConnexion.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")); } public String getDerniereConnexionRelative() { if (derniereConnexion == null) return "Jamais connecté"; long jours = ChronoUnit.DAYS.between(derniereConnexion, LocalDateTime.now()); if (jours == 0) return "Aujourd'hui"; if (jours == 1) return "Hier"; if (jours < 7) return "Il y a " + jours + " jours"; if (jours < 30) return "Il y a " + (jours / 7) + " semaine(s)"; return "Il y a " + (jours / 30) + " mois"; } } public static class NouvelUtilisateur { private String nom; private String prenom; private String email; private String telephone; private String role; private UUID organisationId; private String motDePasse; private boolean envoyerEmail; // Getters et setters public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; } public String getPrenom() { return prenom; } public void setPrenom(String prenom) { this.prenom = prenom; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public UUID getOrganisationId() { return organisationId; } public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; } public String getMotDePasse() { return motDePasse; } public void setMotDePasse(String motDePasse) { this.motDePasse = motDePasse; } public boolean isEnvoyerEmail() { return envoyerEmail; } public void setEnvoyerEmail(boolean envoyerEmail) { this.envoyerEmail = envoyerEmail; } } public static class Filtres { private String recherche; private String role; private String statut; private String connexion; private UUID organisation; // Getters et setters public String getRecherche() { return recherche; } public void setRecherche(String recherche) { this.recherche = recherche; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public String getStatut() { return statut; } public void setStatut(String statut) { this.statut = statut; } public String getConnexion() { return connexion; } public void setConnexion(String connexion) { this.connexion = connexion; } public UUID getOrganisation() { return organisation; } public void setOrganisation(UUID organisation) { this.organisation = organisation; } } public static class StatistiquesUtilisateurs { private int totalUtilisateurs; private int utilisateursConnectes; private int administrateurs; private int utilisateursDesactives; // Getters et setters public int getTotalUtilisateurs() { return totalUtilisateurs; } public void setTotalUtilisateurs(int totalUtilisateurs) { this.totalUtilisateurs = totalUtilisateurs; } public int getUtilisateursConnectes() { return utilisateursConnectes; } public void setUtilisateursConnectes(int utilisateursConnectes) { this.utilisateursConnectes = utilisateursConnectes; } public int getAdministrateurs() { return administrateurs; } public void setAdministrateurs(int administrateurs) { this.administrateurs = administrateurs; } public int getUtilisateursDesactives() { return utilisateursDesactives; } public void setUtilisateursDesactives(int utilisateursDesactives) { this.utilisateursDesactives = utilisateursDesactives; } } public static class Organisation { private UUID id; private String nom; // Getters et setters public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; } } }