Refactoring - Version stable

This commit is contained in:
dahoud
2026-03-28 16:51:14 +00:00
parent 4d096a4791
commit 40a2dd9728
5 changed files with 296 additions and 0 deletions

View File

@@ -674,6 +674,33 @@ public class MembreResource {
.build();
}
@PUT
@Path("/{id}/promouvoir-admin-organisation")
@RolesAllowed({"ADMIN", "SUPER_ADMIN"})
@Operation(
summary = "Promouvoir un membre en administrateur d'organisation",
description = "Passe le membre en statut ACTIF et lui assigne le rôle ADMIN_ORGANISATION dans Keycloak. "
+ "Réservé aux super administrateurs de la plateforme. "
+ "Le compte est immédiatement opérationnel sans validation intermédiaire.")
@APIResponse(responseCode = "200", description = "Membre promu administrateur d'organisation")
@APIResponse(responseCode = "404", description = "Membre non trouvé")
@APIResponse(responseCode = "403", description = "Accès réservé aux ADMIN / SUPER_ADMIN")
public Response promouvoirAdminOrganisation(
@Parameter(description = "UUID du membre à promouvoir") @PathParam("id") UUID id) {
LOG.infof("Promotion admin d'organisation pour le membre ID: %s", id);
Membre membrePromu = membreService.promouvoirAdminOrganisation(id);
// Assigner ADMIN_ORGANISATION dans Keycloak (non bloquant)
try {
keycloakSyncService.promouvoirAdminOrganisationDansKeycloak(id);
} catch (Exception e) {
LOG.warnf("Promotion Keycloak échouée pour %s (non bloquant): %s", membrePromu.getEmail(), e.getMessage());
}
return Response.ok(membreService.convertToResponse(membrePromu)).build();
}
@PUT
@Path("/{id}/activer")
@RolesAllowed({"ADMIN", "SUPER_ADMIN"})

View File

@@ -196,6 +196,62 @@ public class MembreKeycloakSyncService {
}
}
/**
* Promeut un membre au rôle ADMIN_ORGANISATION dans Keycloak.
* Appelé après MembreService.promouvoirAdminOrganisation().
*
* <p>Si le membre n'a pas encore de compte Keycloak, le provisionne d'abord.
* Assigne ensuite ADMIN_ORGANISATION et retire les rôles MEMBRE / MEMBRE_ACTIF
* (un admin gère l'organisation — il n'est pas un membre ordinaire).
*
* @param membreId UUID du membre à promouvoir dans Keycloak
* @throws NotFoundException si le membre n'existe pas en base
*/
@Transactional
public void promouvoirAdminOrganisationDansKeycloak(java.util.UUID membreId) {
LOGGER.info("Promotion Keycloak (rôle ADMIN_ORGANISATION) pour Membre ID: " + membreId);
Membre membre = membreRepository.findByIdOptional(membreId)
.orElseThrow(() -> new NotFoundException("Membre non trouvé avec l'ID: " + membreId));
// Provisionner le compte Keycloak s'il n'existe pas encore
if (membre.getKeycloakId() == null) {
LOGGER.info("Compte Keycloak absent — provisionnement automatique pour " + membre.getNomComplet());
provisionKeycloakUser(membreId);
membre = membreRepository.findByIdOptional(membreId)
.orElseThrow(() -> new NotFoundException("Membre non trouvé après provisionnement: " + membreId));
}
String keycloakUserId = membre.getKeycloakId().toString();
try {
UserDTO user = userServiceClient.getUserById(keycloakUserId, DEFAULT_REALM);
// S'assurer que le compte est activé
if (Boolean.FALSE.equals(user.getEnabled())) {
user.setEnabled(true);
}
// Construire la liste de rôles : ajouter ADMIN_ORGANISATION, retirer MEMBRE et MEMBRE_ACTIF
List<String> roles = user.getRealmRoles() != null
? new java.util.ArrayList<>(user.getRealmRoles())
: new java.util.ArrayList<>();
roles.remove("MEMBRE");
roles.remove("MEMBRE_ACTIF");
if (!roles.contains("ADMIN_ORGANISATION")) {
roles.add("ADMIN_ORGANISATION");
}
user.setRealmRoles(roles);
userServiceClient.updateUser(keycloakUserId, user, DEFAULT_REALM);
LOGGER.info("✅ Rôle ADMIN_ORGANISATION assigné dans Keycloak pour " + membre.getNomComplet());
} catch (Exception e) {
LOGGER.severe("❌ Erreur promotion Keycloak pour " + membre.getNomComplet() + ": " + e.getMessage());
throw new RuntimeException("Impossible de promouvoir le compte Keycloak: " + e.getMessage(), e);
}
}
/**
* Synchronise les données du Membre vers le User Keycloak.
* Si le membre n'a pas de compte Keycloak, le provisionne automatiquement.

View File

@@ -118,6 +118,33 @@ public class MembreService {
return membre;
}
/**
* Promeut un membre au rôle d'administrateur d'organisation.
* Passe immédiatement le statut à ACTIF — les admins sont opérationnels sans
* validation intermédiaire.
* Doit être suivi d'un appel à
* MembreKeycloakSyncService.promouvoirAdminOrganisationDansKeycloak()
* pour que le rôle ADMIN_ORGANISATION soit assigné dans Keycloak.
*
* @param membreId UUID du membre à promouvoir
* @return Le membre mis à jour
* @throws jakarta.ws.rs.NotFoundException si le membre est introuvable
*/
@Transactional
public Membre promouvoirAdminOrganisation(UUID membreId) {
LOG.infof("Promotion admin d'organisation pour le membre ID: %s", membreId);
Membre membre = membreRepository.findByIdOptional(membreId)
.orElseThrow(() -> new jakarta.ws.rs.NotFoundException("Membre non trouvé avec l'ID: " + membreId));
membre.setStatutCompte("ACTIF");
membre.setActif(true);
membreRepository.persist(membre);
LOG.infof("Membre promu admin d'organisation: %s (ID: %s)", membre.getNomComplet(), membreId);
return membre;
}
/** Met à jour un membre existant */
@Transactional
public Membre mettreAJourMembre(UUID id, Membre membreModifie) {