wip: LoggerService

This commit is contained in:
Thibaut Valentin 2025-07-02 23:07:01 +02:00
parent 0c4b88b5cd
commit ad58958f49
6 changed files with 212 additions and 31 deletions

View File

@ -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
}
}

View File

@ -0,0 +1,7 @@
package fr.titionfire.ffsaf.data.model;
public interface LoggableModel {
Long getId();
String getObjectName();
LogModel.ObjectType getObjectType();
}

View File

@ -21,7 +21,7 @@ import java.util.List;
@Entity @Entity
@Table(name = "membre") @Table(name = "membre")
public class MembreModel { public class MembreModel implements LoggableModel {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@ -72,4 +72,14 @@ public class MembreModel {
@OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Schema(description = "Les licences du membre. (optionnel)") @Schema(description = "Les licences du membre. (optionnel)")
List<LicenceModel> licences; List<LicenceModel> licences;
@Override
public String getObjectName() {
return fname + " " + lname;
}
@Override
public LogModel.ObjectType getObjectType() {
return LogModel.ObjectType.Membre;
}
} }

View File

@ -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<LogModel, Long> {
}

View File

@ -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<LogModel> 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);
}
}

View File

@ -69,6 +69,9 @@ public class MembreService {
@Inject @Inject
RegisterRepository registerRepository; RegisterRepository registerRepository;
@Inject
LoggerService ls;
public SimpleCombModel find(int licence, String np) throws Throwable { public SimpleCombModel find(int licence, String np) throws Throwable {
return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() -> return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() ->
repository.find( repository.find(
@ -139,16 +142,6 @@ public class MembreService {
.map(l -> membres.stream().map(m -> SimpleMembreInOutData.fromModel(m, l)).toList())); .map(l -> membres.stream().map(m -> SimpleMembreInOutData.fromModel(m, l)).toList()));
} }
/*
public Uni<List<SimpleMembre>> 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<String> allImporte(String subject, List<SimpleMembreInOutData> data) { public Uni<String> allImporte(String subject, List<SimpleMembreInOutData> data) {
if (data == null) if (data == null)
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
@ -187,40 +180,58 @@ public class MembreService {
return mm; return mm;
}); });
if ((model.getId() != null && StringSimilarity.similarity(model.getLname().toUpperCase(), boolean add = model.getId() == null;
dataIn.getNom() Uni<Void> log = Uni.createFrom().voidItem();
.toUpperCase()) > 3) || (model.getId() != null && StringSimilarity.similarity(
if ((!add && StringSimilarity.similarity(model.getLname().toUpperCase(),
dataIn.getNom().toUpperCase()) > 3) || (!add && StringSimilarity.similarity(
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
throw new DBadRequestException( throw new DBadRequestException(
"Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide."); "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.setLname(dataIn.getNom().toUpperCase());
model.setFname(dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1)); 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.setEmail(dataIn.getEmail());
}
model.setGenre(Genre.fromString(dataIn.getGenre())); model.setGenre(Genre.fromString(dataIn.getGenre()));
if (dataIn.getBirthdate() != null) { 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.setBirth_date(dataIn.getBirthdate());
model.setCategorie(Utils.getCategoryFormBirthDate(model.getBirth_date(), new Date())); model.setCategorie(Utils.getCategoryFormBirthDate(model.getBirth_date(), new Date()));
} }
uniResult = uniResult.call(() -> Panache.withTransaction(() -> repository.persist(model) uniResult = uniResult
.chain(membreModel1 -> dataIn.isLicenceCurrent() ? licenceRepository.find( .call(() -> Panache.withTransaction(() -> repository.persist(model)
"membre.id = ?1 AND saison = ?2", membreModel1.getId(), Utils.getSaison()) .chain(membreModel1 -> dataIn.isLicenceCurrent() ? licenceRepository.find(
.firstResult() "membre.id = ?1 AND saison = ?2", membreModel1.getId(),
.call(l -> { Utils.getSaison())
if (l == null) { .firstResult()
l = new LicenceModel(); .call(l -> {
l.setMembre(membreModel1); if (l == null) {
l.setValidate(false); l = new LicenceModel();
l.setSaison(Utils.getSaison()); l.setMembre(membreModel1);
} l.setValidate(false);
l.setCertificate(dataIn.getCertif()); l.setSaison(Utils.getSaison());
return licenceRepository.persist(l); }
}) : licenceRepository.delete( l.setCertificate(dataIn.getCertif());
"membre = ?1 AND saison = ?2 AND validate = false", membreModel1, return licenceRepository.persist(l);
Utils.getSaison())))); }) : 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; return uniResult;
})) }))