package dev.lions.unionflow.client.view; import dev.lions.unionflow.server.api.dto.admin.response.AuditLogResponse; import dev.lions.unionflow.client.service.AuditService; import dev.lions.unionflow.client.service.NotificationClientService; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.SessionScoped; import jakarta.faces.context.ExternalContext; import jakarta.faces.context.FacesContext; import jakarta.inject.Inject; import jakarta.inject.Named; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.jboss.logging.Logger; import dev.lions.unionflow.client.service.ErrorHandlerService; import dev.lions.unionflow.client.service.RetryService; import java.io.OutputStream; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * Bean JSF pour la gestion des logs d'audit * Refactorisé pour utiliser directement AuditLogResponse et se connecter au backend * * @author UnionFlow Team * @version 2.0 */ @Named("auditBean") @SessionScoped public class AuditBean implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(AuditBean.class); @Inject @RestClient private AuditService auditService; @Inject @RestClient private NotificationClientService notificationService; @Inject private UserSession userSession; @Inject ErrorHandlerService errorHandler; @Inject RetryService retryService; private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); // Filtres private Date dateDebut; private Date dateFin; private String typeAction = ""; private String severite = ""; private String utilisateur = ""; private String module = ""; private String ipAddress = ""; // Données - Utilisation directe de AuditLogResponse private List tousLesLogs; private List logsFiltres; private AuditLogResponse logSelectionne; // Statistiques private Map statistiques; // Export private String formatExport = "EXCEL"; private boolean inclureFiltresExport = true; @PostConstruct public void init() { LOG.info("Initialisation de AuditBean"); // Initialiser les dates à aujourd'hui - 7 jours Calendar cal = Calendar.getInstance(); dateFin = cal.getTime(); cal.add(Calendar.DAY_OF_MONTH, -7); dateDebut = cal.getTime(); chargerLogs(); chargerStatistiques(); } /** * Charge les logs depuis le backend */ public void chargerLogs() { try { LOG.info("Chargement des logs d'audit depuis le backend"); Map response = retryService.executeWithRetrySupplier( () -> auditService.listerTous(0, 1000, "dateHeure", "desc"), "chargement des logs d'audit" ); tousLesLogs = new ArrayList<>(); if (response.containsKey("data")) { @SuppressWarnings("unchecked") List data = (List) response.get("data"); if (data != null) { for (Object item : data) { if (item instanceof AuditLogResponse) { tousLesLogs.add((AuditLogResponse) item); } else if (item instanceof Map) { @SuppressWarnings("unchecked") AuditLogResponse dto = convertMapToDTO((Map) item); tousLesLogs.add(dto); } } } } appliquerFiltres(); LOG.infof("Logs chargés: %d", tousLesLogs.size()); } catch (Exception e) { LOG.errorf(e, "Erreur lors du chargement des logs"); tousLesLogs = new ArrayList<>(); errorHandler.handleException(e, "lors du chargement des logs d'audit", null); } } /** * Charge les statistiques depuis le backend */ public void chargerStatistiques() { try { LOG.info("Chargement des statistiques d'audit"); statistiques = retryService.executeWithRetrySupplier( () -> auditService.getStatistiques(), "chargement des statistiques d'audit" ); } catch (Exception e) { LOG.errorf(e, "Erreur lors du chargement des statistiques"); statistiques = new HashMap<>(); statistiques.put("total", 0L); statistiques.put("success", 0L); statistiques.put("errors", 0L); statistiques.put("warnings", 0L); } } /** * Convertit une Map en AuditLogResponse */ private AuditLogResponse convertMapToDTO(Map map) { AuditLogResponse dto = new AuditLogResponse(); try { if (map.get("id") != null) { if (map.get("id") instanceof UUID) { dto.setId((UUID) map.get("id")); } else { dto.setId(UUID.fromString(map.get("id").toString())); } } if (map.get("typeAction") != null) dto.setTypeAction(map.get("typeAction").toString()); if (map.get("severite") != null) dto.setSeverite(map.get("severite").toString()); if (map.get("utilisateur") != null) dto.setUtilisateur(map.get("utilisateur").toString()); if (map.get("role") != null) dto.setRole(map.get("role").toString()); if (map.get("module") != null) dto.setModule(map.get("module").toString()); if (map.get("description") != null) dto.setDescription(map.get("description").toString()); if (map.get("details") != null) dto.setDetails(map.get("details").toString()); if (map.get("ipAddress") != null) dto.setIpAddress(map.get("ipAddress").toString()); if (map.get("userAgent") != null) dto.setUserAgent(map.get("userAgent").toString()); if (map.get("sessionId") != null) dto.setSessionId(map.get("sessionId").toString()); if (map.get("donneesAvant") != null) dto.setDonneesAvant(map.get("donneesAvant").toString()); if (map.get("donneesApres") != null) dto.setDonneesApres(map.get("donneesApres").toString()); if (map.get("entiteId") != null) dto.setEntiteId(map.get("entiteId").toString()); if (map.get("entiteType") != null) dto.setEntiteType(map.get("entiteType").toString()); // Conversion des dates if (map.get("dateHeure") != null) { Object date = map.get("dateHeure"); if (date instanceof LocalDateTime) { dto.setDateHeure((LocalDateTime) date); } else if (date instanceof String) { dto.setDateHeure(LocalDateTime.parse(date.toString())); } } } catch (Exception e) { LOG.warnf(e, "Erreur lors de la conversion Map vers DTO"); } return dto; } /** * Applique les filtres sur les logs */ public void appliquerFiltres() { if (tousLesLogs == null) { logsFiltres = new ArrayList<>(); return; } logsFiltres = tousLesLogs.stream() .filter(this::correspondAuxFiltres) .collect(Collectors.toList()); } private boolean correspondAuxFiltres(AuditLogResponse log) { if (log.getDateHeure() == null) return false; // Filtre par dates LocalDateTime dateDebutLDT = dateDebut != null ? LocalDateTime.ofInstant(dateDebut.toInstant(), ZoneId.systemDefault()) : null; LocalDateTime dateFinLDT = dateFin != null ? LocalDateTime.ofInstant(dateFin.toInstant(), ZoneId.systemDefault()).plusDays(1) : null; if (dateDebutLDT != null && log.getDateHeure().isBefore(dateDebutLDT)) { return false; } if (dateFinLDT != null && log.getDateHeure().isAfter(dateFinLDT)) { return false; } // Filtre par type d'action if (!typeAction.isEmpty() && !typeAction.equals(log.getTypeAction())) { return false; } // Filtre par sévérité if (!severite.isEmpty() && !severite.equals(log.getSeverite())) { return false; } // Filtre par utilisateur if (!utilisateur.isEmpty() && log.getUtilisateur() != null && !log.getUtilisateur().toLowerCase().contains(utilisateur.toLowerCase())) { return false; } // Filtre par module if (!module.isEmpty() && !module.equals(log.getModule())) { return false; } // Filtre par IP if (!ipAddress.isEmpty() && log.getIpAddress() != null && !log.getIpAddress().contains(ipAddress)) { return false; } return true; } /** * Recherche avec filtres via le backend */ public void rechercher() { try { LOG.info("Recherche de logs avec filtres"); String dateDebutStr = dateDebut != null ? LocalDateTime.ofInstant(dateDebut.toInstant(), ZoneId.systemDefault()).toString() : null; String dateFinStr = dateFin != null ? LocalDateTime.ofInstant(dateFin.toInstant(), ZoneId.systemDefault()).toString() : null; Map response = retryService.executeWithRetrySupplier( () -> auditService.rechercher( dateDebutStr, dateFinStr, typeAction.isEmpty() ? null : typeAction, severite.isEmpty() ? null : severite, utilisateur.isEmpty() ? null : utilisateur, module.isEmpty() ? null : module, ipAddress.isEmpty() ? null : ipAddress, 0, 1000), "recherche de logs d'audit" ); logsFiltres = new ArrayList<>(); if (response.containsKey("data")) { @SuppressWarnings("unchecked") List data = (List) response.get("data"); if (data != null) { for (Object item : data) { if (item instanceof AuditLogResponse) { logsFiltres.add((AuditLogResponse) item); } else if (item instanceof Map) { @SuppressWarnings("unchecked") AuditLogResponse dto = convertMapToDTO((Map) item); logsFiltres.add(dto); } } } } errorHandler.showSuccess("Recherche", logsFiltres.size() + " log(s) trouvé(s)"); } catch (Exception e) { LOG.errorf(e, "Erreur lors de la recherche"); errorHandler.handleException(e, "lors de la recherche de logs d'audit", null); } } /** * Réinitialise les filtres */ public void reinitialiserFiltres() { Calendar cal = Calendar.getInstance(); dateFin = cal.getTime(); cal.add(Calendar.DAY_OF_MONTH, -7); dateDebut = cal.getTime(); typeAction = ""; severite = ""; utilisateur = ""; module = ""; ipAddress = ""; appliquerFiltres(); } /** * Actualise les données */ public void actualiser() { chargerLogs(); chargerStatistiques(); } /** * Sélectionne un log pour voir les détails */ public void selectionnerLog(AuditLogResponse log) { this.logSelectionne = log; } /** * Méthode pour compatibilité avec l'ancienne page */ public void voirDetails(AuditLogResponse log) { selectionnerLog(log); } /** * Signale un événement d'audit suspect */ public void signalerEvenement(AuditLogResponse log) { if (log == null) { errorHandler.showWarning("Attention", "Aucun log sélectionné"); return; } try { LOG.infof("Signalement de l'événement: %s", log.getId()); // Envoyer une notification aux administrateurs String message = String.format( "Événement signalé - Type: %s, Utilisateur: %s, Date: %s, IP: %s", log.getTypeAction(), log.getUtilisateur(), log.getDateHeure() != null ? log.getDateHeure().format(DATE_FORMATTER) : "N/A", log.getIpAddress() ); // Récupérer l'ID de l'utilisateur courant pour le signalement String signaleurId = userSession.getCurrentUser() != null ? userSession.getCurrentUser().getId().toString() : "anonyme"; retryService.executeWithRetrySupplier( () -> { notificationService.envoyerNotificationGroupe( "SYSTEME", "Signalement d'un événement d'audit", message, List.of(signaleurId) // Envoyer aux admins (à adapter selon votre logique) ); return null; }, "envoi d'une notification de signalement" ); errorHandler.showSuccess("Signalement", "L'événement a été signalé aux administrateurs"); } catch (Exception e) { LOG.errorf(e, "Erreur lors du signalement"); errorHandler.handleException(e, "lors du signalement d'un événement d'audit", null); } } /** * Exporte les logs d'audit en CSV */ public void exporter() { try { LOG.infof("Export de %d logs d'audit", logsFiltres != null ? logsFiltres.size() : 0); List logsAExporter = logsFiltres != null && !logsFiltres.isEmpty() ? logsFiltres : tousLesLogs; if (logsAExporter == null || logsAExporter.isEmpty()) { errorHandler.showWarning("Attention", "Aucun log à exporter"); return; } // Générer le CSV StringBuilder csv = new StringBuilder(); csv.append("Date/Heure;Type Action;Utilisateur;Module;IP;Sévérité;Détails\n"); for (AuditLogResponse log : logsAExporter) { csv.append(String.format("%s;%s;%s;%s;%s;%s;%s\n", log.getDateHeure() != null ? log.getDateHeure().format(DATE_FORMATTER) : "", log.getTypeAction() != null ? log.getTypeAction() : "", log.getUtilisateur() != null ? log.getUtilisateur() : "", log.getModule() != null ? log.getModule() : "", log.getIpAddress() != null ? log.getIpAddress() : "", log.getSeverite() != null ? log.getSeverite() : "", log.getDetails() != null ? log.getDetails().replace(";", ",").replace("\n", " ") : "" )); } byte[] csvData = csv.toString().getBytes(StandardCharsets.UTF_8); telechargerFichier(csvData, "audit-logs-export.csv", "text/csv"); errorHandler.showSuccess("Export", "Export de " + logsAExporter.size() + " log(s) terminé"); } catch (Exception e) { LOG.errorf(e, "Erreur lors de l'export"); errorHandler.handleException(e, "lors de l'export des logs d'audit", null); } } /** * Télécharge un fichier via le navigateur */ private void telechargerFichier(byte[] data, String nomFichier, String contentType) { try { FacesContext fc = FacesContext.getCurrentInstance(); ExternalContext ec = fc.getExternalContext(); ec.responseReset(); ec.setResponseContentType(contentType + "; charset=UTF-8"); ec.setResponseContentLength(data.length); ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + nomFichier + "\""); OutputStream output = ec.getResponseOutputStream(); output.write(data); output.flush(); fc.responseComplete(); } catch (Exception e) { LOG.errorf(e, "Erreur téléchargement fichier"); throw new RuntimeException("Erreur lors du téléchargement", e); } } // Getters pour KPIs public int getTotalEvenements() { if (statistiques != null && statistiques.containsKey("total")) { Object total = statistiques.get("total"); if (total instanceof Number) { return ((Number) total).intValue(); } } return tousLesLogs != null ? tousLesLogs.size() : 0; } public long getConnexionsReussies() { if (tousLesLogs == null) return 0; LocalDateTime aujourdhui = LocalDateTime.now().toLocalDate().atStartOfDay(); return tousLesLogs.stream() .filter(log -> "CONNEXION".equals(log.getTypeAction()) && "SUCCESS".equals(log.getSeverite()) && log.getDateHeure() != null && log.getDateHeure().isAfter(aujourdhui)) .count(); } public long getTentativesEchouees() { if (tousLesLogs == null) return 0; LocalDateTime semainePassee = LocalDateTime.now().minusWeeks(1); return tousLesLogs.stream() .filter(log -> "CONNEXION".equals(log.getTypeAction()) && !"SUCCESS".equals(log.getSeverite()) && log.getDateHeure() != null && log.getDateHeure().isAfter(semainePassee)) .count(); } public long getAlertesSecurite() { if (tousLesLogs == null) return 0; return tousLesLogs.stream() .filter(log -> "CRITICAL".equals(log.getSeverite()) || "ERROR".equals(log.getSeverite())) .count(); } // Getters et Setters public Date getDateDebut() { return dateDebut; } public void setDateDebut(Date dateDebut) { this.dateDebut = dateDebut; appliquerFiltres(); } public Date getDateFin() { return dateFin; } public void setDateFin(Date dateFin) { this.dateFin = dateFin; appliquerFiltres(); } public String getTypeAction() { return typeAction; } public void setTypeAction(String typeAction) { this.typeAction = typeAction; appliquerFiltres(); } public String getSeverite() { return severite; } public void setSeverite(String severite) { this.severite = severite; appliquerFiltres(); } public String getUtilisateur() { return utilisateur; } public void setUtilisateur(String utilisateur) { this.utilisateur = utilisateur; appliquerFiltres(); } public String getModule() { return module; } public void setModule(String module) { this.module = module; appliquerFiltres(); } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; appliquerFiltres(); } public List getEvenementsFiltres() { return logsFiltres != null ? logsFiltres : new ArrayList<>(); } public AuditLogResponse getEvenementSelectionne() { return logSelectionne; } public void setEvenementSelectionne(AuditLogResponse log) { this.logSelectionne = log; } public String getFormatExport() { return formatExport; } public void setFormatExport(String formatExport) { this.formatExport = formatExport; } public boolean isInclureFiltresExport() { return inclureFiltresExport; } public void setInclureFiltresExport(boolean inclureFiltresExport) { this.inclureFiltresExport = inclureFiltresExport; } }