diff --git a/dossierfacile-api-owner/README.md b/dossierfacile-api-owner/README.md new file mode 100644 index 000000000..866695089 --- /dev/null +++ b/dossierfacile-api-owner/README.md @@ -0,0 +1,9 @@ +# API Propriétaire (dossierfacile-api-owner) + +## Description +API REST dédiée à l'espace propriétaires, permettant la gestion et la consultation des dossiers des locataires. + +## Fonctionnalités principales +- Création et gestion des comptes propriétaires +- Partage de ses propriétés avec les candidats locataires +- Consultation des dossiers partagés par les locataires \ No newline at end of file diff --git a/dossierfacile-api-owner/src/main/java/fr/dossierfacile/api/dossierfacileapiowner/user/OwnerMapper.java b/dossierfacile-api-owner/src/main/java/fr/dossierfacile/api/dossierfacileapiowner/user/OwnerMapper.java index 1b6365dfe..ba2ee22f1 100644 --- a/dossierfacile-api-owner/src/main/java/fr/dossierfacile/api/dossierfacileapiowner/user/OwnerMapper.java +++ b/dossierfacile-api-owner/src/main/java/fr/dossierfacile/api/dossierfacileapiowner/user/OwnerMapper.java @@ -5,8 +5,11 @@ import fr.dossierfacile.common.entity.ApartmentSharing; import fr.dossierfacile.common.entity.Owner; import fr.dossierfacile.common.entity.Property; +import fr.dossierfacile.common.enums.TenantFileStatus; + import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Named; import org.springframework.stereotype.Component; @Component @@ -20,7 +23,15 @@ public abstract class OwnerMapper { @Mapping( target="totalGuarantorSalary", expression="java(apartmentSharing.totalGuarantorSalary())" ) public abstract ApartmentSharingModel apartmentSharingToApartmentSharingModel(ApartmentSharing apartmentSharing); - @Mapping( target="propertyApartmentSharingCount", expression="java(property.getPropertiesApartmentSharing().size())" ) - @Mapping( source="dpeDate", target="dpeDate", dateFormat="yyyy-MM-dd") + @Mapping( source="property", target="propertyApartmentSharingCount", qualifiedByName="validApplicationsCount" ) + @Mapping( source="dpeDate", target="dpeDate", dateFormat="yyyy-MM-dd" ) public abstract LightPropertyModel toLightPropertyModel(Property property); + + @Named("validApplicationsCount") + public static int getValidApplicationsCount(Property property) { + long count = property.getPropertiesApartmentSharing().stream() + .filter(p -> !p.getApartmentSharing().getStatus().equals(TenantFileStatus.ARCHIVED)) + .count(); + return (int) count; + } } diff --git a/dossierfacile-api-owner/src/main/resources/application.properties b/dossierfacile-api-owner/src/main/resources/application.properties index 03a33190f..6d4223c0b 100644 --- a/dossierfacile-api-owner/src/main/resources/application.properties +++ b/dossierfacile-api-owner/src/main/resources/application.properties @@ -38,7 +38,7 @@ logging.level.root=info logging.file.path=logs logging.logstash.destination= -application.api.version=3 +application.api.version=4 application.name=api-owner environment= diff --git a/dossierfacile-api-tenant/README.md b/dossierfacile-api-tenant/README.md new file mode 100644 index 000000000..eed8c9677 --- /dev/null +++ b/dossierfacile-api-tenant/README.md @@ -0,0 +1,14 @@ +# API Locataire (dossierfacile-api-tenant) + +## Description +API REST dédiée aux locataires, permettant la gestion des dossiers de location. +API REST dédiée aux utilisateurs de DossierFacile (DFC), permettant la visualisation des informations des locataires. + +## Fonctionnalités principales +- Création et gestion de comptes locataires +- Téléversement et gestion des justificatifs +- Création et modification de dossiers +- Partage de dossiers + +## Documentation de l'API DFC +La documentation Swagger est accessible [ici](https://api-preprod.dossierfacile.fr/swagger-ui/index.html?urls.primaryName=API%20DFC). \ No newline at end of file diff --git a/dossierfacile-api-tenant/pom.xml b/dossierfacile-api-tenant/pom.xml index 8c3b128f9..48acbc8a6 100644 --- a/dossierfacile-api-tenant/pom.xml +++ b/dossierfacile-api-tenant/pom.xml @@ -31,7 +31,7 @@ org.keycloak keycloak-admin-client - 26.0.2 + 26.0.3 org.springframework.boot diff --git a/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/CustomAppender.java b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/CustomAppender.java new file mode 100644 index 000000000..46d10885b --- /dev/null +++ b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/CustomAppender.java @@ -0,0 +1,61 @@ +package fr.dossierfacile.api.front.log; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.IThrowableProxy; +import ch.qos.logback.classic.spi.StackTraceElementProxy; +import ch.qos.logback.core.AppenderBase; +import ch.qos.logback.core.Context; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class CustomAppender extends AppenderBase { + private static final Map> logsByRequestId = new ConcurrentHashMap<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + String requestId = MDC.get("request_id"); + if (requestId != null) { + String message = eventObject.getFormattedMessage(); + + if (eventObject.getLevel().isGreaterOrEqual(Level.ERROR)) { + IThrowableProxy throwableProxy = eventObject.getThrowableProxy(); + if (throwableProxy != null) { + StringBuilder stackTrace = new StringBuilder(); + for (StackTraceElementProxy line : throwableProxy.getStackTraceElementProxyArray()) { + stackTrace.append(line).append("\n"); + } + message += "\n" + stackTrace; + } + } + + LogModel log = new LogModel(message, eventObject.getLevel()); + logsByRequestId.computeIfAbsent(requestId, id -> new ArrayList<>()) + .add(log); + } + } + + public static List getLogsForRequest(String requestId) { + return logsByRequestId.getOrDefault(requestId, List.of()); + } + + public static void clearLogsForRequest(String requestId) { + logsByRequestId.remove(requestId); + } + + public static void attachToRootLogger() { + Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + CustomAppender customAppender = new CustomAppender(); + customAppender.setName("CUSTOM"); + Context context = rootLogger.getLoggerContext(); + customAppender.setContext(context); + customAppender.start(); + rootLogger.addAppender(customAppender); + } +} diff --git a/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/GlobalExceptionHandler.java b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/GlobalExceptionHandler.java new file mode 100644 index 000000000..6dd39131d --- /dev/null +++ b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/GlobalExceptionHandler.java @@ -0,0 +1,18 @@ +package fr.dossierfacile.api.front.log; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e) { + log.error("Unhandled exception: ", e); + return new ResponseEntity<>("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR); + } +} \ No newline at end of file diff --git a/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogAggregationFilter.java b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogAggregationFilter.java new file mode 100644 index 000000000..d372efb0b --- /dev/null +++ b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogAggregationFilter.java @@ -0,0 +1,72 @@ +package fr.dossierfacile.api.front.log; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.LoggingEvent; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import net.logstash.logback.appender.LogstashTcpSocketAppender; +import org.jetbrains.annotations.NotNull; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class LogAggregationFilter extends OncePerRequestFilter { + private LogstashTcpSocketAppender logstashAppender; + + @PostConstruct + public void init() { + Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + logstashAppender = (LogstashTcpSocketAppender) rootLogger.getAppender("LOGSTASH"); + if (logstashAppender == null) { + throw new IllegalStateException("Logstash appender (LOGSTASH) not found in Logback configuration."); + } + } + + @Override + protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + String requestId = MDC.get("request_id"); + try { + filterChain.doFilter(request, response); + } finally { + List logs = CustomAppender.getLogsForRequest(requestId); + String logMessage = logs.stream().map(LogModel::getMessage).collect(Collectors.joining()); + + String enrichedLogs = String.format( + "Request completed: URI:%s, Method:%s, Status:%d, Logs:%s", + request.getRequestURI(), + request.getMethod(), + response.getStatus(), + logMessage + ); + + Level logLevel = logs.stream().map(LogModel::getLevel).max(Comparator.comparingInt(Level::toInt)).orElse(Level.INFO); + + LoggingEvent enrichedEvent = new LoggingEvent(); + enrichedEvent.setTimeStamp(System.currentTimeMillis()); + enrichedEvent.setLoggerName("AggregatedHttpLogger"); + enrichedEvent.setLevel(logLevel); + enrichedEvent.setThreadName(Thread.currentThread().getName()); + enrichedEvent.setMessage(enrichedLogs); + + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + enrichedEvent.setLoggerContext(loggerContext); + + logstashAppender.doAppend(enrichedEvent); + + CustomAppender.clearLogsForRequest(requestId); + } + } +} diff --git a/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogConfiguration.java b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogConfiguration.java new file mode 100644 index 000000000..893bee565 --- /dev/null +++ b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogConfiguration.java @@ -0,0 +1,14 @@ +package fr.dossierfacile.api.front.log; + +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class LogConfiguration { + + @PostConstruct + public void setupCustomLogging() { + CustomAppender.attachToRootLogger(); + } +} \ No newline at end of file diff --git a/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogModel.java b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogModel.java new file mode 100644 index 000000000..4b5f255ea --- /dev/null +++ b/dossierfacile-api-tenant/src/main/java/fr/dossierfacile/api/front/log/LogModel.java @@ -0,0 +1,15 @@ +package fr.dossierfacile.api.front.log; + +import ch.qos.logback.classic.Level; +import lombok.Getter; + +@Getter +public class LogModel { + String message; + Level level; + + public LogModel(String message, Level level) { + this.message = message; + this.level = level; + } +} diff --git a/dossierfacile-api-tenant/src/main/resources/application.properties b/dossierfacile-api-tenant/src/main/resources/application.properties index 4040ee54e..0ec58c92a 100644 --- a/dossierfacile-api-tenant/src/main/resources/application.properties +++ b/dossierfacile-api-tenant/src/main/resources/application.properties @@ -77,7 +77,7 @@ logging.logstash.destination= # Swagger springdoc.api-docs.groups.enabled=true -application.api.version=3 +application.api.version=4 application.name=api-tenant application.base.url= tenant.base.url= diff --git a/dossierfacile-api-tenant/src/main/resources/logback-spring-delayed.xml b/dossierfacile-api-tenant/src/main/resources/logback-spring-delayed.xml index 135363ba8..d353f25e5 100644 --- a/dossierfacile-api-tenant/src/main/resources/logback-spring-delayed.xml +++ b/dossierfacile-api-tenant/src/main/resources/logback-spring-delayed.xml @@ -56,9 +56,11 @@ + + diff --git a/dossierfacile-api-watermark/src/main/resources/application.properties b/dossierfacile-api-watermark/src/main/resources/application.properties index 9b97b9cd2..bf339cfad 100644 --- a/dossierfacile-api-watermark/src/main/resources/application.properties +++ b/dossierfacile-api-watermark/src/main/resources/application.properties @@ -44,6 +44,6 @@ logging.logstash.destination= file.retention.days=1 cron.process.cleanup=0 0 0 * * ? -application.api.version=3 +application.api.version=4 application.name=api-watermark environment= \ No newline at end of file diff --git a/dossierfacile-bo/src/main/resources/application.properties b/dossierfacile-bo/src/main/resources/application.properties index 73623e218..a105893cd 100644 --- a/dossierfacile-bo/src/main/resources/application.properties +++ b/dossierfacile-bo/src/main/resources/application.properties @@ -66,7 +66,7 @@ logging.level.root=info logging.file.path=logs logging.logstash.destination= -application.api.version=3 +application.api.version=4 application.name=bo environment= application.base.url= diff --git a/dossierfacile-common-library/README.md b/dossierfacile-common-library/README.md index 752b99ac9..083874315 100644 --- a/dossierfacile-common-library/README.md +++ b/dossierfacile-common-library/README.md @@ -1,3 +1,10 @@ -# DossierFacile-common-library +# Bibliothèque commune (dossierfacile-common-library) -This project contains shared models, repositories, mappers, services, ... used by Dossier-Facile's services. \ No newline at end of file +## Description +Bibliothèque partagée contenant les composants communs utilisés par les différents services du projet. + +## Composants principaux +- Entités JPA communes +- Services partagés +- Configurations communes +- Ressources utilitaires \ No newline at end of file diff --git a/dossierfacile-pdf-generator/README.md b/dossierfacile-pdf-generator/README.md index 822e1c9db..472569f0d 100644 --- a/dossierfacile-pdf-generator/README.md +++ b/dossierfacile-pdf-generator/README.md @@ -1,37 +1,8 @@ -# Dossier-Facile-Pdf-Generator -Dossier Facile PDF Generator +# Générateur de fichiers PDF (dossierfacile-pdf-generator) +## Description +Service dédié à la génération de documents PDF. -# Install and run - -To build: `mvn clean install` -To run: `mvn spring-boot:run ` - -## Requirements -- running DossierFacile database -- running rabbitMQ service - -## Configure - -We use Github package to store common library `dossierfacile-common-library` . -Thus you need to authenticate yourself to get it on github package. - -Configure the following environement variables: -``` -GITHUB_USERNAME -GITHUB_TOKEN -``` -Or use your global maven settings: .m2/settings.xml -``` - - ... - - - github - GITHUB_USERNAME - GITHUB_TOKEN - - - ... - -``` \ No newline at end of file +## Fonctionnalités principales +- Conversion de documents et fichiers en PDF avec filigrane +- Génération de dossiers de location au format PDF \ No newline at end of file diff --git a/dossierfacile-pdf-generator/src/main/resources/application.properties b/dossierfacile-pdf-generator/src/main/resources/application.properties index 1f25fb767..a319a406a 100644 --- a/dossierfacile-pdf-generator/src/main/resources/application.properties +++ b/dossierfacile-pdf-generator/src/main/resources/application.properties @@ -40,7 +40,7 @@ logging.level.root=info logging.file.path=logs logging.logstash.destination= -application.api.version=3 +application.api.version=4 application.name=pdf-generator environment= diff --git a/dossierfacile-process-file/README.md b/dossierfacile-process-file/README.md new file mode 100644 index 000000000..35c24221a --- /dev/null +++ b/dossierfacile-process-file/README.md @@ -0,0 +1,9 @@ +# Service de traitement asynchrone des fichiers et docuemnts (dossierfacile-process-file) + +## Description +Service responsable du traitement asynchrone des documents et des fichiers. + +## Fonctionnalités principales +- Miniaturisation des fichiers +- Extraction des données (OCR, lecture 2D Doc, ...) +- Analyse des documents \ No newline at end of file diff --git a/dossierfacile-process-file/src/main/resources/application.properties b/dossierfacile-process-file/src/main/resources/application.properties index bcc7e09f1..893fcecfd 100644 --- a/dossierfacile-process-file/src/main/resources/application.properties +++ b/dossierfacile-process-file/src/main/resources/application.properties @@ -41,7 +41,7 @@ logging.level.root=info logging.file.path=logs logging.logstash.destination= -application.api.version=3 +application.api.version=4 application.name=process-file environment= diff --git a/dossierfacile-task-scheduler/README.md b/dossierfacile-task-scheduler/README.md new file mode 100644 index 000000000..1f5dc7f61 --- /dev/null +++ b/dossierfacile-task-scheduler/README.md @@ -0,0 +1,11 @@ +# Service de gestion des tâches asynchrones (dossierfacile-task-scheduler) + +## Description +Module responsable de la planification et de l'exécution des tâches récurrentes dans DossierFacile. + +## Tâches principales +- Vérification de la disponibilité de l'API de l'ADEME +- Gestion des documents en erreur dans les dossiers (tentative de génération, suppression) +- Gestion de la synchronisation des fichiers sur les stockages +- Nettoyage des fichiers sur les stockages +- Gestion des opérations asynchrones sur les comptes (messages de warning, archivage, suppression) diff --git a/dossierfacile-task-scheduler/src/main/resources/application.properties b/dossierfacile-task-scheduler/src/main/resources/application.properties index d1b19f9c6..68a1a6cd9 100644 --- a/dossierfacile-task-scheduler/src/main/resources/application.properties +++ b/dossierfacile-task-scheduler/src/main/resources/application.properties @@ -57,6 +57,6 @@ logging.level.root=info logging.file.path=logs logging.logstash.destination= -application.api.version=3 +application.api.version=4 application.name=task-scheduler environment= \ No newline at end of file diff --git a/pom.xml b/pom.xml index b07e9656a..eb1c84b8a 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ ${java.version} 1.6.2 1.18.34 - 22.0.5 + 26.0.3 2.17.1 0.0.1-SNAPSHOT 7.4