fix: Ajout des classes Entity et Mapper manquantes pour Audit
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
package dev.lions.user.manager.server.impl.entity;
|
||||
|
||||
import dev.lions.user.manager.enums.audit.TypeActionAudit;
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Entité JPA pour la persistance des logs d'audit en base de données PostgreSQL.
|
||||
*
|
||||
* <p>Cette entité représente un enregistrement d'audit qui track toutes les actions
|
||||
* effectuées sur les utilisateurs du système (création, modification, suppression, etc.).</p>
|
||||
*
|
||||
* <p><b>Utilisation:</b></p>
|
||||
* <pre>
|
||||
* AuditLogEntity auditLog = new AuditLogEntity();
|
||||
* auditLog.setUserId("user-123");
|
||||
* auditLog.setAction(TypeActionAudit.CREATION_UTILISATEUR);
|
||||
* auditLog.setDetails("Utilisateur créé avec succès");
|
||||
* auditLog.setAuteurAction("admin");
|
||||
* auditLog.setTimestamp(LocalDateTime.now());
|
||||
* auditLog.persist();
|
||||
* </pre>
|
||||
*
|
||||
* @see dev.lions.user.manager.server.api.dto.AuditLogDTO
|
||||
* @see TypeActionAudit
|
||||
* @author Lions Development Team
|
||||
* @version 1.0.0
|
||||
* @since 2026-01-02
|
||||
*/
|
||||
@Entity
|
||||
@Table(
|
||||
name = "audit_logs",
|
||||
indexes = {
|
||||
@Index(name = "idx_audit_user_id", columnList = "user_id"),
|
||||
@Index(name = "idx_audit_action", columnList = "action"),
|
||||
@Index(name = "idx_audit_timestamp", columnList = "timestamp"),
|
||||
@Index(name = "idx_audit_auteur", columnList = "auteur_action")
|
||||
}
|
||||
)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class AuditLogEntity extends PanacheEntity {
|
||||
|
||||
/**
|
||||
* ID de l'utilisateur concerné par l'action.
|
||||
* <p>Peut être null pour les actions système qui ne concernent pas un utilisateur spécifique.</p>
|
||||
*/
|
||||
@Column(name = "user_id", length = 255)
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Type d'action effectuée (CREATION_UTILISATEUR, MODIFICATION_UTILISATEUR, etc.).
|
||||
* <p>Stocké en tant que STRING pour faciliter la lecture en base de données.</p>
|
||||
*/
|
||||
@Column(name = "action", nullable = false, length = 100)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TypeActionAudit action;
|
||||
|
||||
/**
|
||||
* Détails complémentaires sur l'action effectuée.
|
||||
* <p>Peut contenir des informations contextuelles comme les champs modifiés,
|
||||
* les raisons d'une action, ou des messages d'erreur.</p>
|
||||
*/
|
||||
@Column(name = "details", columnDefinition = "TEXT")
|
||||
private String details;
|
||||
|
||||
/**
|
||||
* Identifiant de l'utilisateur qui a effectué l'action.
|
||||
* <p>Généralement l'username ou l'ID de l'administrateur/utilisateur connecté.</p>
|
||||
*/
|
||||
@Column(name = "auteur_action", nullable = false, length = 255)
|
||||
private String auteurAction;
|
||||
|
||||
/**
|
||||
* Timestamp précis de l'action.
|
||||
* <p>Utilisé pour l'ordre chronologique des logs et le filtrage temporel.</p>
|
||||
*/
|
||||
@Column(name = "timestamp", nullable = false)
|
||||
private LocalDateTime timestamp;
|
||||
|
||||
/**
|
||||
* Adresse IP de l'auteur de l'action.
|
||||
* <p>Utile pour la traçabilité et la détection d'anomalies.</p>
|
||||
*/
|
||||
@Column(name = "ip_address", length = 45)
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* User-Agent du client (navigateur, application, etc.).
|
||||
* <p>Permet d'identifier le type de client utilisé pour l'action.</p>
|
||||
*/
|
||||
@Column(name = "user_agent", length = 500)
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* Nom du realm Keycloak concerné.
|
||||
* <p>Important dans un environnement multi-tenant pour isoler les logs par realm.</p>
|
||||
*/
|
||||
@Column(name = "realm_name", length = 255)
|
||||
private String realmName;
|
||||
|
||||
/**
|
||||
* Indique si l'action a réussi ou échoué.
|
||||
* <p>Permet de filtrer facilement les actions en erreur pour analyse.</p>
|
||||
*/
|
||||
@Column(name = "success", nullable = false)
|
||||
private Boolean success = true;
|
||||
|
||||
/**
|
||||
* Message d'erreur en cas d'échec de l'action.
|
||||
* <p>Null si success = true.</p>
|
||||
*/
|
||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* Constructeur par défaut requis par JPA.
|
||||
*/
|
||||
public AuditLogEntity() {
|
||||
this.timestamp = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche tous les logs d'audit pour un utilisateur donné.
|
||||
*
|
||||
* @param userId ID de l'utilisateur
|
||||
* @return Liste des logs triés par timestamp décroissant
|
||||
*/
|
||||
public static java.util.List<AuditLogEntity> findByUserId(String userId) {
|
||||
return list("userId = ?1 order by timestamp desc", userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche tous les logs d'audit d'un type d'action donné.
|
||||
*
|
||||
* @param action Type d'action
|
||||
* @return Liste des logs triés par timestamp décroissant
|
||||
*/
|
||||
public static java.util.List<AuditLogEntity> findByAction(TypeActionAudit action) {
|
||||
return list("action = ?1 order by timestamp desc", action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche tous les logs d'audit pour un auteur donné.
|
||||
*
|
||||
* @param auteurAction Identifiant de l'auteur
|
||||
* @return Liste des logs triés par timestamp décroissant
|
||||
*/
|
||||
public static java.util.List<AuditLogEntity> findByAuteur(String auteurAction) {
|
||||
return list("auteurAction = ?1 order by timestamp desc", auteurAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche tous les logs d'audit dans une période donnée.
|
||||
*
|
||||
* @param startDate Date de début (inclusive)
|
||||
* @param endDate Date de fin (inclusive)
|
||||
* @return Liste des logs dans la période, triés par timestamp décroissant
|
||||
*/
|
||||
public static java.util.List<AuditLogEntity> findByPeriod(LocalDateTime startDate, LocalDateTime endDate) {
|
||||
return list("timestamp >= ?1 and timestamp <= ?2 order by timestamp desc", startDate, endDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche tous les logs d'audit pour un realm donné.
|
||||
*
|
||||
* @param realmName Nom du realm
|
||||
* @return Liste des logs triés par timestamp décroissant
|
||||
*/
|
||||
public static java.util.List<AuditLogEntity> findByRealm(String realmName) {
|
||||
return list("realmName = ?1 order by timestamp desc", realmName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime tous les logs d'audit plus anciens qu'une date donnée.
|
||||
* <p>Utile pour la maintenance et le respect des politiques de rétention.</p>
|
||||
*
|
||||
* @param beforeDate Date limite (les logs avant cette date seront supprimés)
|
||||
* @return Nombre de logs supprimés
|
||||
*/
|
||||
public static long deleteOlderThan(LocalDateTime beforeDate) {
|
||||
return delete("timestamp < ?1", beforeDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compte le nombre d'actions effectuées par un auteur donné.
|
||||
*
|
||||
* @param auteurAction Identifiant de l'auteur
|
||||
* @return Nombre d'actions
|
||||
*/
|
||||
public static long countByAuteur(String auteurAction) {
|
||||
return count("auteurAction = ?1", auteurAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compte le nombre d'échecs pour un utilisateur donné.
|
||||
* <p>Utile pour détecter des problèmes récurrents.</p>
|
||||
*
|
||||
* @param userId ID de l'utilisateur
|
||||
* @return Nombre d'échecs
|
||||
*/
|
||||
public static long countFailuresByUserId(String userId) {
|
||||
return count("userId = ?1 and success = false", userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package dev.lions.user.manager.server.impl.mapper;
|
||||
|
||||
import dev.lions.user.manager.dto.audit.AuditLogDTO;
|
||||
import dev.lions.user.manager.server.impl.entity.AuditLogEntity;
|
||||
import org.mapstruct.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mapper MapStruct pour la conversion entre AuditLogEntity (JPA) et AuditLogDTO (API).
|
||||
*
|
||||
* <p>Ce mapper gère la transformation bidirectionnelle entre l'entité de persistance
|
||||
* et le DTO exposé via l'API REST, avec mapping automatique des champs compatibles.</p>
|
||||
*
|
||||
* <p><b>Fonctionnalités:</b></p>
|
||||
* <ul>
|
||||
* <li>Conversion Entity → DTO pour lecture/API</li>
|
||||
* <li>Conversion DTO → Entity pour persistance</li>
|
||||
* <li>Mapping de listes pour opérations bulk</li>
|
||||
* <li>Gestion automatique des types LocalDateTime</li>
|
||||
* <li>Mapping des enums (TypeActionAudit)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>Utilisation:</b></p>
|
||||
* <pre>
|
||||
* {@literal @}Inject
|
||||
* AuditLogMapper mapper;
|
||||
*
|
||||
* // Entity → DTO
|
||||
* AuditLogDTO dto = mapper.toDTO(entity);
|
||||
*
|
||||
* // DTO → Entity
|
||||
* AuditLogEntity entity = mapper.toEntity(dto);
|
||||
*
|
||||
* // Liste Entity → Liste DTO
|
||||
* List<AuditLogDTO> dtos = mapper.toDTOList(entities);
|
||||
* </pre>
|
||||
*
|
||||
* @see AuditLogEntity
|
||||
* @see AuditLogDTO
|
||||
* @author Lions Development Team
|
||||
* @version 1.0.0
|
||||
* @since 2026-01-02
|
||||
*/
|
||||
@Mapper(
|
||||
componentModel = MappingConstants.ComponentModel.JAKARTA_CDI,
|
||||
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
|
||||
unmappedTargetPolicy = ReportingPolicy.IGNORE
|
||||
)
|
||||
public interface AuditLogMapper {
|
||||
|
||||
/**
|
||||
* Convertit une entité AuditLogEntity en DTO AuditLogDTO.
|
||||
*
|
||||
* <p>Mapping des champs Entity → DTO:</p>
|
||||
* <ul>
|
||||
* <li>id (Long) → id (String)</li>
|
||||
* <li>userId → ressourceId</li>
|
||||
* <li>action → typeAction</li>
|
||||
* <li>details → description</li>
|
||||
* <li>auteurAction → acteurUsername</li>
|
||||
* <li>timestamp → dateAction</li>
|
||||
* <li>ipAddress → ipAddress</li>
|
||||
* <li>userAgent → userAgent</li>
|
||||
* <li>realmName → realmName</li>
|
||||
* <li>success → success</li>
|
||||
* <li>errorMessage → errorMessage</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param entity L'entité JPA à convertir (peut être null)
|
||||
* @return Le DTO correspondant, ou null si l'entité est null
|
||||
*/
|
||||
@Mapping(target = "id", source = "id", qualifiedByName = "longToString")
|
||||
@Mapping(target = "ressourceId", source = "userId")
|
||||
@Mapping(target = "typeAction", source = "action")
|
||||
@Mapping(target = "description", source = "details")
|
||||
@Mapping(target = "acteurUsername", source = "auteurAction")
|
||||
@Mapping(target = "dateAction", source = "timestamp")
|
||||
AuditLogDTO toDTO(AuditLogEntity entity);
|
||||
|
||||
/**
|
||||
* Convertit un DTO AuditLogDTO en entité AuditLogEntity.
|
||||
*
|
||||
* <p>Utilisé pour créer une nouvelle entité à persister depuis les données API.</p>
|
||||
*
|
||||
* <p><b>Note:</b> L'ID de l'entité sera null (auto-généré par la DB),
|
||||
* même si l'ID du DTO est renseigné.</p>
|
||||
*
|
||||
* @param dto Le DTO à convertir (peut être null)
|
||||
* @return L'entité JPA correspondante, ou null si le DTO est null
|
||||
*/
|
||||
@Mapping(target = "id", ignore = true) // L'ID sera généré par la DB
|
||||
@Mapping(target = "userId", source = "ressourceId")
|
||||
@Mapping(target = "action", source = "typeAction")
|
||||
@Mapping(target = "details", source = "description")
|
||||
@Mapping(target = "auteurAction", source = "acteurUsername")
|
||||
@Mapping(target = "timestamp", source = "dateAction")
|
||||
AuditLogEntity toEntity(AuditLogDTO dto);
|
||||
|
||||
/**
|
||||
* Convertit une liste d'entités en liste de DTOs.
|
||||
*
|
||||
* <p>Utile pour les recherches qui retournent plusieurs résultats.</p>
|
||||
*
|
||||
* @param entities Liste des entités à convertir (peut être null ou vide)
|
||||
* @return Liste des DTOs correspondants, ou liste vide si entities est null/vide
|
||||
*/
|
||||
List<AuditLogDTO> toDTOList(List<AuditLogEntity> entities);
|
||||
|
||||
/**
|
||||
* Convertit une liste de DTOs en liste d'entités.
|
||||
*
|
||||
* <p>Utile pour les opérations d'import ou de création en masse.</p>
|
||||
*
|
||||
* @param dtos Liste des DTOs à convertir (peut être null ou vide)
|
||||
* @return Liste des entités correspondantes, ou liste vide si dtos est null/vide
|
||||
*/
|
||||
List<AuditLogEntity> toEntityList(List<AuditLogDTO> dtos);
|
||||
|
||||
/**
|
||||
* Met à jour une entité existante avec les données d'un DTO.
|
||||
*
|
||||
* <p>Préserve l'ID de l'entité et ne met à jour que les champs
|
||||
* présents dans le DTO.</p>
|
||||
*
|
||||
* <p><b>Utilisation:</b></p>
|
||||
* <pre>
|
||||
* AuditLogEntity existingEntity = AuditLogEntity.findById(id);
|
||||
* mapper.updateEntityFromDTO(dto, existingEntity);
|
||||
* existingEntity.persist();
|
||||
* </pre>
|
||||
*
|
||||
* @param dto Le DTO source contenant les nouvelles valeurs
|
||||
* @param entity L'entité cible à mettre à jour
|
||||
*/
|
||||
@Mapping(target = "id", ignore = true) // Préserve l'ID existant
|
||||
@Mapping(target = "userId", source = "ressourceId")
|
||||
@Mapping(target = "action", source = "typeAction")
|
||||
@Mapping(target = "details", source = "description")
|
||||
@Mapping(target = "auteurAction", source = "acteurUsername")
|
||||
@Mapping(target = "timestamp", source = "dateAction")
|
||||
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
|
||||
void updateEntityFromDTO(AuditLogDTO dto, @MappingTarget AuditLogEntity entity);
|
||||
|
||||
/**
|
||||
* Convertit un Long (ID de l'entité) en String (ID du DTO).
|
||||
*
|
||||
* <p>MapStruct appelle automatiquement cette méthode pour le mapping de l'ID.</p>
|
||||
*
|
||||
* @param id L'ID de type Long (peut être null)
|
||||
* @return L'ID converti en String, ou null si l'input est null
|
||||
*/
|
||||
@Named("longToString")
|
||||
default String longToString(Long id) {
|
||||
return id != null ? id.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit un String (ID du DTO) en Long (ID de l'entité).
|
||||
*
|
||||
* <p>Utilisé lors de la conversion DTO → Entity si nécessaire.</p>
|
||||
*
|
||||
* @param id L'ID de type String (peut être null)
|
||||
* @return L'ID converti en Long, ou null si l'input est null ou invalide
|
||||
*/
|
||||
@Named("stringToLong")
|
||||
default Long stringToLong(String id) {
|
||||
if (id == null || id.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(id);
|
||||
} catch (NumberFormatException e) {
|
||||
// Log warning et retourne null en cas de format invalide
|
||||
System.err.println("WARN: Invalid ID format for conversion to Long: " + id);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user