From ad58958f495f36eb8409d7f5d31859152b3a4674 Mon Sep 17 00:00:00 2001 From: Thibaut Valentin Date: Wed, 2 Jul 2025 23:07:01 +0200 Subject: [PATCH] wip: LoggerService --- .../titionfire/ffsaf/data/model/LogModel.java | 45 +++++++++ .../ffsaf/data/model/LoggableModel.java | 7 ++ .../ffsaf/data/model/MembreModel.java | 12 ++- .../ffsaf/data/repository/LogRepository.java | 9 ++ .../ffsaf/domain/service/LoggerService.java | 99 +++++++++++++++++++ .../ffsaf/domain/service/MembreService.java | 71 +++++++------ 6 files changed, 212 insertions(+), 31 deletions(-) create mode 100644 src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java create mode 100644 src/main/java/fr/titionfire/ffsaf/data/model/LoggableModel.java create mode 100644 src/main/java/fr/titionfire/ffsaf/data/repository/LogRepository.java create mode 100644 src/main/java/fr/titionfire/ffsaf/domain/service/LoggerService.java diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java new file mode 100644 index 0000000..b3d170c --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/model/LogModel.java @@ -0,0 +1,45 @@ +package fr.titionfire.ffsaf.data.model; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.persistence.*; +import lombok.*; + +import java.util.Date; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@RegisterForReflection + +@Entity +@Table(name = "log") +public class LogModel { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + String subject; + + Date dateTime; + + ActionType action; + + ObjectType object; + + Long target_id; + + String target_name; + + String message; + + public enum ActionType { + ADD, REMOVE, UPDATE + } + + public enum ObjectType { + Membre, Affiliation, Licence, Club, Competition, Register + } + +} diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/LoggableModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/LoggableModel.java new file mode 100644 index 0000000..d90657a --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/model/LoggableModel.java @@ -0,0 +1,7 @@ +package fr.titionfire.ffsaf.data.model; + +public interface LoggableModel { + Long getId(); + String getObjectName(); + LogModel.ObjectType getObjectType(); +} diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java index 4ca338b..b39db64 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java @@ -21,7 +21,7 @@ import java.util.List; @Entity @Table(name = "membre") -public class MembreModel { +public class MembreModel implements LoggableModel { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -72,4 +72,14 @@ public class MembreModel { @OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @Schema(description = "Les licences du membre. (optionnel)") List licences; + + @Override + public String getObjectName() { + return fname + " " + lname; + } + + @Override + public LogModel.ObjectType getObjectType() { + return LogModel.ObjectType.Membre; + } } diff --git a/src/main/java/fr/titionfire/ffsaf/data/repository/LogRepository.java b/src/main/java/fr/titionfire/ffsaf/data/repository/LogRepository.java new file mode 100644 index 0000000..efad118 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/repository/LogRepository.java @@ -0,0 +1,9 @@ +package fr.titionfire.ffsaf.data.repository; + +import fr.titionfire.ffsaf.data.model.LogModel; +import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class LogRepository implements PanacheRepositoryBase { +} diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/LoggerService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/LoggerService.java new file mode 100644 index 0000000..f658850 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/LoggerService.java @@ -0,0 +1,99 @@ +package fr.titionfire.ffsaf.domain.service; + +import fr.titionfire.ffsaf.data.model.LogModel; +import fr.titionfire.ffsaf.data.model.LogModel.ActionType; +import fr.titionfire.ffsaf.data.model.LogModel.ObjectType; +import fr.titionfire.ffsaf.data.model.LoggableModel; +import fr.titionfire.ffsaf.data.repository.LogRepository; +import fr.titionfire.ffsaf.utils.SecurityCtx; +import io.quarkus.hibernate.reactive.panache.Panache; +import io.quarkus.hibernate.reactive.panache.common.WithSession; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +@WithSession +@RequestScoped +public class LoggerService { + + @Inject + LogRepository repository; + + @Inject + SecurityCtx securityCtx; + + private final List buffer = new ArrayList<>(); + + public Uni logA(ActionType action, ObjectType object, String message, String target_name, Long target_id) { + System.out.println("log"); + return Panache.withTransaction(() -> repository.persist( + new LogModel(null, securityCtx.getSubject(), new Date(), action, object, target_id, target_name, + message))); + } + + public Uni logA(ActionType action, String message, LoggableModel model) { + return logA(action, model.getObjectType(), message, model.getObjectName(), model.getId()); + } + + public Uni logAAdd(LoggableModel model) { + return logA(ActionType.ADD, "", model); + } + + public Uni logAUpdate(String message, LoggableModel model) { + return logA(ActionType.UPDATE, message, model); + } + + public Uni logAChange(String champ, Object o1, Object o2, LoggableModel model) { + System.out.println(o1 + " " + o2); + if (Objects.equals(o1, o2)) + return Uni.createFrom().nullItem(); + return logA(ActionType.UPDATE, champ + ": " + o1.toString() + " -> " + o2.toString(), model); + } + + public Uni logADelete(LoggableModel model) { + return logA(ActionType.REMOVE, "", model); + } + + public Uni append() { + return Panache.withTransaction(() -> repository.persist(buffer)) + .invoke(__ -> buffer.clear()); + } + + public void clear() { + buffer.clear(); + } + + public void log(ActionType action, ObjectType object, String message, String target_name, Long target_id) { + System.out.println("log"); + buffer.add(new LogModel(null, securityCtx.getSubject(), new Date(), action, object, target_id, target_name, + message)); + } + + public void log(ActionType action, String message, LoggableModel model) { + log(action, model.getObjectType(), message, model.getObjectName(), model.getId()); + } + + public void logAdd(LoggableModel model) { + log(ActionType.ADD, "", model); + } + + public void logUpdate(String message, LoggableModel model) { + log(ActionType.UPDATE, message, model); + } + + public void logChange(String champ, Object o1, Object o2, LoggableModel model) { + System.out.println(o1 + " " + o2); + if (Objects.equals(o1, o2)) + return; + log(ActionType.UPDATE, champ + ": " + o1.toString() + " -> " + o2.toString(), model); + } + + public void logDelete(LoggableModel model) { + log(ActionType.REMOVE, "", model); + } +} diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java index f508c04..e3614be 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java @@ -69,6 +69,9 @@ public class MembreService { @Inject RegisterRepository registerRepository; + @Inject + LoggerService ls; + public SimpleCombModel find(int licence, String np) throws Throwable { return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() -> repository.find( @@ -139,16 +142,6 @@ public class MembreService { .map(l -> membres.stream().map(m -> SimpleMembreInOutData.fromModel(m, l)).toList())); } - /* - - public Uni> getSimilar(String fname, String lname) { - return repository.listAll().map(membreModels -> membreModels.stream() - .filter(m -> StringSimilarity.similarity(m.getFname(), fname) <= 3 && - StringSimilarity.similarity(m.getLname(), lname) <= 3) - .map(SimpleMembre::fromModel).toList()); - }+ - */ - public Uni allImporte(String subject, List data) { if (data == null) return Uni.createFrom().nullItem(); @@ -187,40 +180,58 @@ public class MembreService { return mm; }); - if ((model.getId() != null && StringSimilarity.similarity(model.getLname().toUpperCase(), - dataIn.getNom() - .toUpperCase()) > 3) || (model.getId() != null && StringSimilarity.similarity( + boolean add = model.getId() == null; + Uni log = Uni.createFrom().voidItem(); + + if ((!add && StringSimilarity.similarity(model.getLname().toUpperCase(), + dataIn.getNom().toUpperCase()) > 3) || (!add && StringSimilarity.similarity( model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) { throw new DBadRequestException( "Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide."); } + + ls.logChange("Nom", model.getLname(), dataIn.getNom().toUpperCase(), model); + ls.logChange("Prénom", model.getFname(), + dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model); + model.setLname(dataIn.getNom().toUpperCase()); model.setFname(dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1)); - if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) + + if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) { + ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model); model.setEmail(dataIn.getEmail()); + } model.setGenre(Genre.fromString(dataIn.getGenre())); if (dataIn.getBirthdate() != null) { + if (!Objects.equals(model.getBirth_date().getTime(), dataIn.getBirthdate().getTime())) + ls.logChange("Date de naissance", model.getBirth_date(), dataIn.getBirthdate(), model); model.setBirth_date(dataIn.getBirthdate()); model.setCategorie(Utils.getCategoryFormBirthDate(model.getBirth_date(), new Date())); } - uniResult = uniResult.call(() -> Panache.withTransaction(() -> repository.persist(model) - .chain(membreModel1 -> dataIn.isLicenceCurrent() ? licenceRepository.find( - "membre.id = ?1 AND saison = ?2", membreModel1.getId(), Utils.getSaison()) - .firstResult() - .call(l -> { - if (l == null) { - l = new LicenceModel(); - l.setMembre(membreModel1); - l.setValidate(false); - l.setSaison(Utils.getSaison()); - } - l.setCertificate(dataIn.getCertif()); - return licenceRepository.persist(l); - }) : licenceRepository.delete( - "membre = ?1 AND saison = ?2 AND validate = false", membreModel1, - Utils.getSaison())))); + uniResult = uniResult + .call(() -> Panache.withTransaction(() -> repository.persist(model) + .chain(membreModel1 -> dataIn.isLicenceCurrent() ? licenceRepository.find( + "membre.id = ?1 AND saison = ?2", membreModel1.getId(), + Utils.getSaison()) + .firstResult() + .call(l -> { + if (l == null) { + l = new LicenceModel(); + l.setMembre(membreModel1); + l.setValidate(false); + l.setSaison(Utils.getSaison()); + } + l.setCertificate(dataIn.getCertif()); + return licenceRepository.persist(l); + }) : licenceRepository.delete( + "membre = ?1 AND saison = ?2 AND validate = false", membreModel1, + Utils.getSaison())))); + if (add) + uniResult = uniResult.call(() -> ls.logAAdd(model)); + else + uniResult = uniResult.call(() -> ls.append()); } return uniResult; }))