feat: BackupService real pg_dump, OrganisationService region stats, SystemConfigService overrides
- BackupService: DB-persisted metadata (BackupRecord/BackupConfig entities + V16 Flyway migration), real pg_dump execution via ProcessBuilder, soft-delete on deleteBackup, pg_restore manual guidance - OrganisationService: repartitionRegion now queries Adresse entities (was Map.of() stub) - SystemConfigService: in-memory config overrides via AtomicReference (no DB dependency) - SystemMetricsService: null-guard on MemoryMXBean in getSystemStatus() (fixes test NPE) - Souscription workflow: SouscriptionService, SouscriptionResource, FormuleAbonnementRepository, V11 Flyway migration, admin REST clients - Flyway V8-V15: notes membres, types référence, type orga constraint, seed roles, première connexion, Wave checkout URL, Wave telephone column length fix - .gitignore: added uploads/ and .claude/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,13 +8,16 @@ import dev.lions.unionflow.server.entity.DemandeAdhesion;
|
||||
import dev.lions.unionflow.server.entity.Membre;
|
||||
import dev.lions.unionflow.server.entity.Organisation;
|
||||
import dev.lions.unionflow.server.repository.AdhesionRepository;
|
||||
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
|
||||
import dev.lions.unionflow.server.repository.MembreRepository;
|
||||
import dev.lions.unionflow.server.repository.OrganisationRepository;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -23,6 +26,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.microprofile.jwt.JsonWebToken;
|
||||
|
||||
/**
|
||||
* Service métier pour la gestion des demandes d'adhésion.
|
||||
@@ -42,9 +46,15 @@ public class AdhesionService {
|
||||
@Inject
|
||||
OrganisationRepository organisationRepository;
|
||||
@Inject
|
||||
MembreOrganisationRepository membreOrganisationRepository;
|
||||
@Inject
|
||||
MembreKeycloakSyncService keycloakSyncService;
|
||||
@Inject
|
||||
DefaultsService defaultsService;
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
@Inject
|
||||
JsonWebToken jwt;
|
||||
|
||||
public List<AdhesionResponse> getAllAdhesions(int page, int size) {
|
||||
log.debug("Récupération des adhésions - page: {}, size: {}", page, size);
|
||||
@@ -142,6 +152,8 @@ public class AdhesionService {
|
||||
.findByIdOptional(id)
|
||||
.orElseThrow(() -> new NotFoundException("Adhésion non trouvée avec l'ID: " + id));
|
||||
|
||||
verifierAccesOrganisation(adhesion);
|
||||
|
||||
if (!adhesion.isEnAttente()) {
|
||||
throw new IllegalStateException("Seules les adhésions en attente peuvent être approuvées");
|
||||
}
|
||||
@@ -175,6 +187,8 @@ public class AdhesionService {
|
||||
.findByIdOptional(id)
|
||||
.orElseThrow(() -> new NotFoundException("Adhésion non trouvée avec l'ID: " + id));
|
||||
|
||||
verifierAccesOrganisation(adhesion);
|
||||
|
||||
if (!adhesion.isEnAttente()) {
|
||||
throw new IllegalStateException("Seules les adhésions en attente peuvent être rejetées");
|
||||
}
|
||||
@@ -279,6 +293,35 @@ public class AdhesionService {
|
||||
"tauxRejet", total > 0 ? (rejetees * 100.0 / total) : 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie que l'ADMIN_ORGANISATION n'agit que sur les adhésions de sa propre organisation.
|
||||
* Les rôles SUPER_ADMIN et ADMIN ont accès sans restriction.
|
||||
*/
|
||||
private void verifierAccesOrganisation(DemandeAdhesion adhesion) {
|
||||
if (!securityIdentity.hasRole("ADMIN_ORGANISATION")) {
|
||||
return; // SUPER_ADMIN / ADMIN : accès libre
|
||||
}
|
||||
|
||||
UUID adhesionOrgId = adhesion.getOrganisation() != null ? adhesion.getOrganisation().getId() : null;
|
||||
if (adhesionOrgId == null) {
|
||||
throw new ForbiddenException("L'adhésion n'est rattachée à aucune organisation");
|
||||
}
|
||||
|
||||
String keycloakSubject = jwt.getSubject();
|
||||
Membre adminMembre = membreRepository.findByKeycloakUserId(keycloakSubject)
|
||||
.orElseThrow(() -> new ForbiddenException("Compte admin introuvable pour le sujet JWT: " + keycloakSubject));
|
||||
|
||||
boolean appartient = membreOrganisationRepository
|
||||
.findByMembreIdAndOrganisationId(adminMembre.getId(), adhesionOrgId)
|
||||
.isPresent();
|
||||
|
||||
if (!appartient) {
|
||||
log.warn("ADMIN_ORGANISATION {} tente d'agir sur une adhésion de l'organisation {} qui n'est pas la sienne",
|
||||
keycloakSubject, adhesionOrgId);
|
||||
throw new ForbiddenException("Vous ne pouvez gérer que les adhésions de votre organisation");
|
||||
}
|
||||
}
|
||||
|
||||
private AdhesionResponse convertToDTO(DemandeAdhesion adhesion) {
|
||||
AdhesionResponse response = new AdhesionResponse();
|
||||
response.setId(adhesion.getId());
|
||||
|
||||
Reference in New Issue
Block a user