security: Sécurisation complète des Resources REST avec @RolesAllowed

Sécurisation de 12 Resources (100% couverture):

AdhesionResource (8 annotations):
- Classe: ADMIN, MEMBRE, USER
- DELETE (1): ADMIN only
- POST (5): ADMIN + MEMBRE
- PUT (1): ADMIN + MEMBRE

AuditResource (2 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (1): ADMIN + MEMBRE

ComptabiliteResource (5 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (3): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

CotisationResource (4 annotations):
- Classe: ADMIN, MEMBRE, USER
- DELETE (1): ADMIN only
- POST (2): ADMIN + MEMBRE
- PUT (1): ADMIN + MEMBRE

DashboardResource (2 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (1): ADMIN + MEMBRE

DocumentResource (5 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (3): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

ExportResource (4 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (2): ADMIN + MEMBRE

NotificationResource (6 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (4): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

OrganisationResource (15 modifications):
- Classe: ADMIN, MEMBRE, USER (remplace @Authenticated)
- DELETE (1): ADMIN only
- POST (3): ADMIN + MEMBRE
- PUT (1): ADMIN + MEMBRE
- Suppression: 7 @PermitAll, 1 @Authenticated

PaiementResource (6 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (3): ADMIN + MEMBRE
- PUT (1): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

TypeOrganisationResource (5 annotations):
- Classe: ADMIN, MEMBRE, USER
- DELETE (1): ADMIN only
- POST (1): ADMIN + MEMBRE
- PUT (1): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

WaveResource (7 annotations):
- Classe: ADMIN, MEMBRE, USER
- POST (4): ADMIN + MEMBRE
- PUT (2): ADMIN + MEMBRE
- Suppression: 2 @PermitAll

Stratégie de sécurité:
- GET: ADMIN, MEMBRE, USER (lecture)
- POST/PUT: ADMIN, MEMBRE (création/modification)
- DELETE: ADMIN only (suppression critique)

Statistiques:
- 69 annotations @RolesAllowed ajoutées
- 18 @PermitAll supprimés
- 1 @Authenticated remplacé
- 100% Resources sécurisées (sauf HealthResource public)
- Compilation réussie

Voir RAPPORT_SECURITE_RESOURCES.md pour détails complets
This commit is contained in:
dahoud
2025-12-04 00:10:04 +00:00
parent c25164c35b
commit 35ddcb1d2d
19 changed files with 418 additions and 314 deletions

View File

@@ -72,11 +72,11 @@ public class ConfigurationBean implements Serializable {
private Boolean chiffrementBDD = true;
// Propriétés d'état système
private String tempsActivite = "99.8%";
private Integer utilisateursConnectes = 247;
private Integer memoireUtilisee = 68;
private String memoireTotal = "16";
private String derniereSauvegarde = "02:00";
private String tempsActivite = "N/A";
private Integer utilisateursConnectes = 0;
private Integer memoireUtilisee = 0;
private String memoireTotal = "N/A";
private String derniereSauvegarde = "N/A";
// Monitoring avancé
private Integer cpuUtilisation = 45;
@@ -107,18 +107,16 @@ public class ConfigurationBean implements Serializable {
}
private void calculerMetriquesSysteme() {
// Simulation des métriques système réelles pour UnionFlow
cpuUtilisation = (int) (Math.random() * 30) + 40; // 40-70%
memoireUtilisee = (int) (Math.random() * 20) + 60; // 60-80%
disqueDisponible = (float) (Math.random() * 50) + 100; // 100-150 GB
connexionsBDDActives = (int) (Math.random() * 10) + 10; // 10-20
queueEmailsEnAttente = (int) (Math.random() * 50) + 10; // 10-60
logsErreurs24h = (int) (Math.random() * 20) + 5; // 5-25
sessionsActives = utilisateursConnectes; // Basé sur utilisateurs connectés
// Optimisé pour la stratégie volume (127 organisations, 247 utilisateurs)
utilisateursConnectes = 247;
sessionsActives = 127; // Une session par organisation active
// TODO: Récupérer les métriques système depuis un service de monitoring
// Pour l'instant, initialiser avec des valeurs par défaut
cpuUtilisation = 0;
memoireUtilisee = 0;
disqueDisponible = 0.0f;
connexionsBDDActives = 0;
queueEmailsEnAttente = 0;
logsErreurs24h = 0;
utilisateursConnectes = 0;
sessionsActives = 0;
}
private void initializeGeneral() {

View File

@@ -70,11 +70,11 @@ public class EntitesGestionBean implements Serializable {
statistiques.setTotalMembres(totalMembres);
double moyenne = associations.isEmpty() ? 0 : (double) totalMembres / associations.size();
statistiques.setMoyenneMembresParEntite((int) moyenne);
statistiques.setRevenus("0 FCFA"); // À calculer depuis les souscriptions
statistiques.setSouscriptionsExpirantes(0); // À calculer
statistiques.setEntitesQuotaAtteint(0); // À calculer
statistiques.setFormulairePopulaire("Standard");
statistiques.setTauxRenouvellement(94.2f);
statistiques.setRevenus("0 FCFA"); // TODO: Calculer depuis les souscriptions/paiements réels
statistiques.setSouscriptionsExpirantes(0); // TODO: Calculer depuis les souscriptions expirantes
statistiques.setEntitesQuotaAtteint(0); // TODO: Calculer depuis les entités avec quota atteint
statistiques.setFormulairePopulaire("N/A"); // TODO: Calculer depuis les statistiques de souscription
statistiques.setTauxRenouvellement(0.0f); // TODO: Calculer depuis les statistiques de renouvellement
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalEntites(0);
@@ -114,25 +114,13 @@ public class EntitesGestionBean implements Serializable {
entite.setDescription(dto.getDescription());
entite.setDerniereActivite(dto.getDateDerniereActivite());
// Définir le forfait selon le nombre de membres
int nbMembres = dto.getNombreMembres() != null ? dto.getNombreMembres() : 0;
if (nbMembres <= 100) {
entite.setForfaitSouscrit("Starter");
entite.setMembresQuota(100);
entite.setMontantMensuel("2 000 FCFA");
} else if (nbMembres <= 200) {
entite.setForfaitSouscrit("Standard");
entite.setMembresQuota(200);
entite.setMontantMensuel("3 000 FCFA");
} else if (nbMembres <= 500) {
entite.setForfaitSouscrit("Premium");
entite.setMembresQuota(500);
entite.setMontantMensuel("4 000 FCFA");
} else {
entite.setForfaitSouscrit("Cristal");
entite.setMembresQuota(2000);
entite.setMontantMensuel("5 000 FCFA");
}
// TODO: Récupérer les informations de souscription depuis un service dédié
// Pour l'instant, initialiser avec des valeurs par défaut
entite.setForfaitSouscrit("Non défini");
entite.setMembresQuota(0);
entite.setMontantMensuel("0 FCFA");
entite.setDateExpirationSouscription(null);
entite.setStatutSouscription("NON_DEFINI");
return entite;
}

View File

@@ -29,69 +29,10 @@ public class RolesBean implements Serializable {
}
private void initialiserRoles() {
// Initialiser avec une liste vide - les rôles seront chargés depuis le backend quand le service sera disponible
roles = new ArrayList<>();
// Rôles système
roles.add(new Role("SUPER_ADMIN", "Super Administrateur",
"Accès complet à toutes les fonctionnalités du système",
TypeRole.SYSTEME, StatutRole.ACTIF, "pi pi-crown", "#ff6b6b", "#ffffff",
Arrays.asList("GESTION_COMPLETE", "ADMIN_SYSTEME", "SUPER_USER"), 3,
LocalDateTime.now().minusDays(1), "Système"));
roles.add(new Role("ADMIN_PLATEFORME", "Administrateur Plateforme",
"Administration des organisations et utilisateurs",
TypeRole.SYSTEME, StatutRole.ACTIF, "pi pi-shield", "#4ecdc4", "#ffffff",
Arrays.asList("GESTION_ORGS", "GESTION_USERS", "RAPPORTS"), 15,
LocalDateTime.now().minusDays(2), "Admin Système"));
roles.add(new Role("ADMIN_ORGANISATION", "Administrateur Organisation",
"Administration d'une organisation spécifique",
TypeRole.SYSTEME, StatutRole.ACTIF, "pi pi-building", "#45b7d1", "#ffffff",
Arrays.asList("GESTION_MEMBRES", "GESTION_EVENTS", "COTISATIONS"), 28,
LocalDateTime.now().minusDays(3), "Super Admin"));
roles.add(new Role("MEMBRE_ACTIF", "Membre Actif",
"Membre participant aux activités de l'organisation",
TypeRole.SYSTEME, StatutRole.ACTIF, "pi pi-users", "#96ceb4", "#ffffff",
Arrays.asList("CONSULTATION", "PARTICIPATION", "PROFIL"), 156,
LocalDateTime.now().minusDays(1), "Admin Org"));
// Rôles personnalisés
roles.add(new Role("COMPTABLE", "Gestionnaire Comptabilité",
"Gestion de la comptabilité et des finances",
TypeRole.PERSONNALISE, StatutRole.ACTIF, "pi pi-calculator", "#feca57", "#333333",
Arrays.asList("COMPTABILITE", "RAPPORTS_FINANCIERS", "COTISATIONS"), 8,
LocalDateTime.now().minusHours(12), "Jean Dupont"));
roles.add(new Role("SECRETAIRE", "Secrétaire",
"Gestion des documents et communications",
TypeRole.PERSONNALISE, StatutRole.ACTIF, "pi pi-file-edit", "#a55eea", "#ffffff",
Arrays.asList("DOCUMENTS", "COMMUNICATIONS", "ARCHIVES"), 5,
LocalDateTime.now().minusDays(5), "Marie Martin"));
roles.add(new Role("MODERATEUR_EVENTS", "Modérateur Événements",
"Organisation et modération des événements",
TypeRole.PERSONNALISE, StatutRole.ACTIF, "pi pi-calendar", "#fd79a8", "#ffffff",
Arrays.asList("GESTION_EVENTS", "MODERATION", "PLANNING"), 12,
LocalDateTime.now().minusHours(6), "Pierre Durand"));
roles.add(new Role("AUDITEUR", "Auditeur Interne",
"Contrôle et audit des activités",
TypeRole.TEMPORAIRE, StatutRole.ACTIF, "pi pi-eye", "#6c5ce7", "#ffffff",
Arrays.asList("AUDIT", "RAPPORTS", "CONSULTATION_COMPLETE"), 2,
LocalDateTime.now().minusHours(2), "Admin Système"));
roles.add(new Role("GUEST_OBSERVER", "Observateur Invité",
"Accès lecture seule temporaire",
TypeRole.TEMPORAIRE, StatutRole.INACTIF, "pi pi-search", "#74b9ff", "#ffffff",
Arrays.asList("CONSULTATION_LIMITEE"), 0,
LocalDateTime.now().minusDays(10), "Marie Martin"));
roles.add(new Role("TRESORIER", "Trésorier",
"Gestion de la trésorerie et budget",
TypeRole.PERSONNALISE, StatutRole.SUSPENDU, "pi pi-money-bill", "#00b894", "#ffffff",
Arrays.asList("TRESORERIE", "BUDGET", "RAPPORTS_FINANCIERS"), 1,
LocalDateTime.now().minusDays(20), "Admin Org"));
// TODO: Charger depuis RoleService quand disponible
// Exemple: roles = roleService.listerTous();
}
// Getters pour les KPIs

View File

@@ -46,6 +46,18 @@ public class SuperAdminBean implements Serializable {
private String croissanceEntites;
private int activiteJournaliere;
// Pourcentages de croissance calculés
private String croissanceMembres = "0";
private String croissanceRevenus = "0";
private int nouvellesEntites = 0;
private int utilisateursActifs = 0;
// Pourcentages pour les progress bars (jauges)
private int pourcentageMembres = 0;
private int pourcentageOrganisations = 0;
private int pourcentageRevenus = 0;
private int pourcentageActivite = 0;
// Métriques de souscription
private int totalSouscriptions;
private int souscriptionsActives;
@@ -85,41 +97,56 @@ public class SuperAdminBean implements Serializable {
}
private void initializeUserInfo() {
// TODO: Récupérer depuis le contexte de sécurité (Keycloak)
nomComplet = "Administrateur Système";
derniereConnexion = LocalDateTime.now().minusHours(2).format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
derniereConnexion = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
}
private void initializeKPIs() {
try {
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
totalEntites = associations.size();
totalAdministrateurs = associations.size(); // À calculer depuis les utilisateurs
totalAdministrateurs = associations.size(); // TODO: Calculer depuis les utilisateurs
int totalMembresCalc = associations.stream()
.mapToInt(a -> a.getNombreMembres() != null ? a.getNombreMembres() : 0)
.sum();
totalMembres = totalMembresCalc;
revenusGlobaux = "0 FCFA"; // À calculer depuis les souscriptions
alertesCount = 0; // À calculer
croissanceEntites = "0"; // À calculer
activiteJournaliere = 0; // À calculer
revenusGlobaux = "0 FCFA"; // TODO: Calculer depuis les souscriptions/paiements réels
alertesCount = 0; // TODO: Calculer depuis les alertes réelles
// Calculer la croissance des entités (comparaison avec le mois précédent)
// Pour l'instant, on ne peut pas calculer sans historique, donc 0
croissanceEntites = "0";
nouvellesEntites = 0; // TODO: Calculer depuis l'historique
// Calculer la croissance des membres (comparaison avec le mois précédent)
// Pour l'instant, on ne peut pas calculer sans historique, donc 0
croissanceMembres = "0"; // TODO: Calculer depuis l'historique des membres
croissanceRevenus = "0"; // TODO: Calculer depuis l'historique des revenus
activiteJournaliere = 0; // TODO: Calculer depuis les logs d'activité
utilisateursActifs = 0; // TODO: Calculer depuis les sessions actives
// Calculer les pourcentages pour les progress bars (jauges)
calculerPourcentagesJauges();
// Initialiser les métriques de souscription
totalSouscriptions = 0; // À calculer depuis les souscriptions
souscriptionsActives = 0; // À calculer
souscriptionsExpirantSous30Jours = 0; // À calculer
tauxConversion = 0.0f; // À calculer
totalSouscriptions = 0; // TODO: Calculer depuis les souscriptions réelles
souscriptionsActives = 0; // TODO: Calculer depuis les souscriptions actives
souscriptionsExpirantSous30Jours = 0; // TODO: Calculer depuis les souscriptions expirantes
tauxConversion = 0.0f; // TODO: Calculer depuis les statistiques de conversion
// Revenus par forfait - À calculer depuis les souscriptions
// Revenus par forfait - TODO: Calculer depuis les souscriptions/paiements réels
revenusStarter = BigDecimal.ZERO;
revenusStandard = BigDecimal.ZERO;
revenusPremmium = BigDecimal.ZERO;
revenusCristal = BigDecimal.ZERO;
// Métriques système
disponibiliteSysteme = 99.8f;
tempsReponsMoyen = 145; // ms
ticketsSupportOuverts = 0; // À calculer
satisfactionClient = 4.7f; // /5
// Métriques système - TODO: Récupérer depuis un service de monitoring
disponibiliteSysteme = 0.0f;
tempsReponsMoyen = 0; // ms
ticketsSupportOuverts = 0; // TODO: Calculer depuis les tickets support réels
satisfactionClient = 0.0f; // /5 - TODO: Calculer depuis les évaluations réelles
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des KPIs: " + e.getMessage());
totalEntites = 0;
@@ -130,62 +157,8 @@ public class SuperAdminBean implements Serializable {
}
private void initializeAlertes() {
// Initialiser avec une liste vide - les alertes seront chargées depuis le backend quand le service sera disponible
alertesRecentes = new ArrayList<>();
// Alertes critiques de souscription
Alerte alerte1 = new Alerte();
alerte1.setId(UUID.fromString("00000000-0000-0000-0000-00000000a001"));
alerte1.setTitre("12 souscriptions expirent sous 30 jours");
alerte1.setEntite("Système - Souscriptions");
alerte1.setDate("Aujourd'hui");
alerte1.setIcone("pi-clock");
alerte1.setCouleur("text-red-500");
alertesRecentes.add(alerte1);
Alerte alerte2 = new Alerte();
alerte2.setId(UUID.fromString("00000000-0000-0000-0000-00000000a002"));
alerte2.setTitre("Quota membre atteint");
alerte2.setEntite("Club Sportif Thiès (Standard)");
alerte2.setDate("Il y a 2h");
alerte2.setIcone("pi-users");
alerte2.setCouleur("text-orange-500");
alertesRecentes.add(alerte2);
Alerte alerte3 = new Alerte();
alerte3.setId(UUID.fromString("00000000-0000-0000-0000-00000000a003"));
alerte3.setTitre("Pic d'inscriptions détecté");
alerte3.setEntite("Association des Femmes Kaolack");
alerte3.setDate("Il y a 4h");
alerte3.setIcone("pi-trending-up");
alerte3.setCouleur("text-green-500");
alertesRecentes.add(alerte3);
Alerte alerte4 = new Alerte();
alerte4.setId(UUID.fromString("00000000-0000-0000-0000-00000000a004"));
alerte4.setTitre("Performance système dégradée");
alerte4.setEntite("Système - Infrastructure");
alerte4.setDate("Il y a 6h");
alerte4.setIcone("pi-exclamation-triangle");
alerte4.setCouleur("text-orange-500");
alertesRecentes.add(alerte4);
Alerte alerte5 = new Alerte();
alerte5.setId(UUID.fromString("00000000-0000-0000-0000-00000000a005"));
alerte5.setTitre("Demande d'upgrade Premium");
alerte5.setEntite("Mutuelle Santé Dakar");
alerte5.setDate("Hier");
alerte5.setIcone("pi-arrow-up");
alerte5.setCouleur("text-blue-500");
alertesRecentes.add(alerte5);
Alerte alerte6 = new Alerte();
alerte6.setId(UUID.fromString("00000000-0000-0000-0000-00000000a006"));
alerte6.setTitre("8 tickets support en attente");
alerte6.setEntite("Support Client");
alerte6.setDate("Il y a 1h");
alerte6.setIcone("pi-comment");
alerte6.setCouleur("text-purple-500");
alertesRecentes.add(alerte6);
}
private void initializeEntites() {
@@ -214,131 +187,41 @@ public class SuperAdminBean implements Serializable {
}
private void initializeRepartitionTypes() {
// Initialiser avec une liste vide - la répartition sera calculée depuis les données réelles quand disponible
repartitionTypes = new ArrayList<>();
TypeEntite clubs = new TypeEntite();
clubs.setNom("Clubs Lions");
clubs.setDescription("Clubs traditionnels");
clubs.setNombre(12);
clubs.setPourcentage(80);
clubs.setIcone("pi-users");
clubs.setCouleurBg("bg-blue-100");
clubs.setCouleurTexte("text-blue-500");
repartitionTypes.add(clubs);
TypeEntite branches = new TypeEntite();
branches.setNom("Branches");
branches.setDescription("Branches spécialisées");
branches.setNombre(2);
branches.setPourcentage(13);
branches.setIcone("pi-sitemap");
branches.setCouleurBg("bg-green-100");
branches.setCouleurTexte("text-green-500");
repartitionTypes.add(branches);
TypeEntite leos = new TypeEntite();
leos.setNom("LEO Clubs");
leos.setDescription("Clubs jeunes");
leos.setNombre(1);
leos.setPourcentage(7);
leos.setIcone("pi-star");
leos.setCouleurBg("bg-orange-100");
leos.setCouleurTexte("text-orange-500");
repartitionTypes.add(leos);
try {
// TODO: Calculer la répartition depuis les données réelles des organisations
// List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
// Grouper par type et calculer les pourcentages
} catch (Exception e) {
LOGGER.warning("Impossible de calculer la répartition des types: " + e.getMessage());
}
}
private void initializeActivites() {
// Initialiser avec une liste vide - les activités seront chargées depuis le backend quand le service sera disponible
activitesRecentes = new ArrayList<>();
String[] descriptions = {
"Nouvelle entité créée",
"Paiement de cotisation validé",
"Membre suspendu",
"Rapport mensuel généré",
"Configuration mise à jour"
};
String[] entites = {
"LIONS CLUB Fatick",
"LIONS CLUB Dakar",
"LIONS CLUB Thiès",
"Système",
"Administration"
};
String[] icones = {
"pi-plus",
"pi-check",
"pi-ban",
"pi-chart-bar",
"pi-cog"
};
String[] utilisateurs = {
"Admin Fatick",
"Jean DIALLO",
"Admin Thiès",
"Système",
"Super Admin"
};
for (int i = 0; i < 5; i++) {
Activite activite = new Activite();
activite.setId(UUID.randomUUID());
activite.setDescription(descriptions[i]);
activite.setEntite(entites[i]);
activite.setIcone(icones[i]);
activite.setDate(LocalDateTime.now().minusHours(i * 2).format(DateTimeFormatter.ofPattern("dd/MM HH:mm")));
activite.setUtilisateur(utilisateurs[i]);
if (i == 1) {
activite.setDetails("Montant: 15 000 FCFA via Wave Money");
}
if (i == 2) {
activite.setDetails("Motif: Non-paiement des cotisations");
}
activitesRecentes.add(activite);
}
// TODO: Charger depuis un service d'audit/logs quand disponible
}
private void initializeEvolution() {
// Initialiser avec une liste vide - l'évolution sera calculée depuis les données réelles quand disponible
evolutionEntites = new ArrayList<>();
String[] periodes = {"Jan", "Fév", "Mar", "Avr", "Mai", "Jun"};
int[] valeurs = {10, 11, 12, 13, 14, 15};
for (int i = 0; i < 6; i++) {
EvolutionMois mois = new EvolutionMois();
mois.setPeriode(periodes[i]);
mois.setValeur(valeurs[i]);
mois.setHauteur(30 + (valeurs[i] * 8)); // Calcul hauteur pour graphique
evolutionEntites.add(mois);
}
// TODO: Calculer l'évolution mensuelle depuis les données historiques des organisations
}
private void initializeRevenus() {
// Initialiser avec des valeurs par défaut - les revenus seront calculés depuis les paiements réels quand disponible
revenus = new RevenusData();
revenus.setMensuel("425 000 FCFA");
revenus.setAnnuel("2 450 000 FCFA");
revenus.setCroissance("15.5");
revenus.setMoyenne("163 333 FCFA");
revenus.setCroissanceMensuelle("8.2");
revenus.setObjectifAnnuel("3 000 000 FCFA");
revenus.setMensuel("0 FCFA");
revenus.setAnnuel("0 FCFA");
revenus.setCroissance("0");
revenus.setMoyenne("0 FCFA");
revenus.setCroissanceMensuelle("0");
revenus.setObjectifAnnuel("0 FCFA");
revenus.setDerniereMAJ(LocalDate.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
// Évolution des revenus
List<MoisRevenu> evolution = new ArrayList<>();
String[] mois = {"Jan", "Fév", "Mar", "Avr", "Mai", "Jun"};
int[] hauteurs = {60, 75, 90, 85, 95, 100};
String[] valeurs = {"380K", "420K", "465K", "445K", "485K", "500K"};
for (int i = 0; i < 6; i++) {
MoisRevenu moisRevenu = new MoisRevenu();
moisRevenu.setNom(mois[i]);
moisRevenu.setHauteur(hauteurs[i]);
moisRevenu.setValeur(valeurs[i]);
evolution.add(moisRevenu);
}
revenus.setEvolution(evolution);
revenus.setEvolution(new ArrayList<>());
// TODO: Calculer depuis les paiements/souscriptions réels quand le service sera disponible
}
// Actions (WOU/DRY - utilisation de navigation outcomes)
@@ -489,6 +372,19 @@ public class SuperAdminBean implements Serializable {
public String getPeriodeEvolution() { return periodeEvolution; }
public void setPeriodeEvolution(String periodeEvolution) { this.periodeEvolution = periodeEvolution; }
// Getters pour les nouvelles propriétés
public String getCroissanceMembres() { return croissanceMembres; }
public void setCroissanceMembres(String croissanceMembres) { this.croissanceMembres = croissanceMembres; }
public String getCroissanceRevenus() { return croissanceRevenus; }
public void setCroissanceRevenus(String croissanceRevenus) { this.croissanceRevenus = croissanceRevenus; }
public int getNouvellesEntites() { return nouvellesEntites; }
public void setNouvellesEntites(int nouvellesEntites) { this.nouvellesEntites = nouvellesEntites; }
public int getUtilisateursActifs() { return utilisateursActifs; }
public void setUtilisateursActifs(int utilisateursActifs) { this.utilisateursActifs = utilisateursActifs; }
// Classes internes
public static class Alerte {
private UUID id;

View File

@@ -59,11 +59,14 @@
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.totalMembres}</div>
<div class="flex align-items-center mb-2">
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.croissanceMembres != null and superAdminBean.croissanceMembres != '0'}">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+12.5%</span>
<span class="text-green-600 font-semibold text-sm mr-2">+#{superAdminBean.croissanceMembres}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.croissanceMembres == null or superAdminBean.croissanceMembres == '0'}">
Données non disponibles
</div>
<p:progressBar value="87"
showValue="false"
styleClass="surface-200"
@@ -84,11 +87,14 @@
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.totalEntites}</div>
<div class="flex align-items-center mb-2">
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.nouvellesEntites > 0}">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+8</span>
<span class="text-green-600 font-semibold text-sm mr-2">+#{superAdminBean.nouvellesEntites}</span>
<span class="text-500 text-xs">nouvelles</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.nouvellesEntites == 0}">
Aucune nouvelle entité ce mois
</div>
<p:progressBar value="92"
showValue="false"
styleClass="surface-200"
@@ -109,11 +115,14 @@
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.revenusGlobaux}</div>
<div class="flex align-items-center mb-2">
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.croissanceRevenus != null and superAdminBean.croissanceRevenus != '0'}">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+23%</span>
<span class="text-green-600 font-semibold text-sm mr-2">+#{superAdminBean.croissanceRevenus}%</span>
<span class="text-500 text-xs">vs mois dernier</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.croissanceRevenus == null or superAdminBean.croissanceRevenus == '0'}">
Données non disponibles
</div>
<p:progressBar value="78"
showValue="false"
styleClass="surface-200"
@@ -134,10 +143,13 @@
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.activiteJournaliere}</div>
<div class="flex align-items-center mb-2">
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.utilisateursActifs > 0}">
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-green-600 font-semibold text-sm mr-2">En ligne</span>
<span class="text-500 text-xs">247 actifs</span>
<span class="text-500 text-xs">#{superAdminBean.utilisateursActifs} actifs</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.utilisateursActifs == 0}">
Aucun utilisateur actif
</div>
<p:progressBar value="65"
showValue="false"