From 9d5e388efada7f5356c44741fd9d8176b4fab9b3 Mon Sep 17 00:00:00 2001 From: dahoud Date: Sat, 24 Jan 2026 09:33:59 +0000 Subject: [PATCH] Refactoring --- pom.xml | 5 ++ .../com/lions/dev/config/OpenAPIConfig.java | 30 +++++++++++ .../lions/dev/dto/PasswordResetRequest.java | 19 +++++++ .../com/lions/dev/resource/UsersResource.java | 45 ++++++++++++++++ .../com/lions/dev/service/UsersService.java | 12 +++++ .../application-production.properties | 54 +++++++++++++++++-- src/main/resources/application.properties | 2 +- .../resources/db/migration/V1__Baseline.sql | 5 ++ 8 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/lions/dev/config/OpenAPIConfig.java create mode 100644 src/main/java/com/lions/dev/dto/PasswordResetRequest.java create mode 100644 src/main/resources/db/migration/V1__Baseline.sql diff --git a/pom.xml b/pom.xml index c16e416..2126784 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,11 @@ io.quarkus quarkus-jsonb + + + io.quarkus + quarkus-flyway + org.projectlombok lombok diff --git a/src/main/java/com/lions/dev/config/OpenAPIConfig.java b/src/main/java/com/lions/dev/config/OpenAPIConfig.java new file mode 100644 index 0000000..4dd7710 --- /dev/null +++ b/src/main/java/com/lions/dev/config/OpenAPIConfig.java @@ -0,0 +1,30 @@ +package com.lions.dev.config; + +import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; +import org.eclipse.microprofile.openapi.annotations.info.Info; +import org.eclipse.microprofile.openapi.annotations.servers.Server; + +import jakarta.ws.rs.core.Application; + +/** + * Configuration OpenAPI pour l'API AfterWork. + * + * Cette classe configure les métadonnées OpenAPI et le serveur de base + * pour que Swagger UI génère correctement les URLs avec le root-path. + */ +@OpenAPIDefinition( + info = @Info( + title = "AfterWork API", + version = "1.0.0", + description = "API REST pour l'application AfterWork - Gestion d'événements, réseaux sociaux et messagerie" + ), + servers = { + @Server( + url = "https://api.lions.dev/afterwork", + description = "Serveur de production" + ) + } +) +public class OpenAPIConfig extends Application { + // Classe de configuration OpenAPI +} diff --git a/src/main/java/com/lions/dev/dto/PasswordResetRequest.java b/src/main/java/com/lions/dev/dto/PasswordResetRequest.java new file mode 100644 index 0000000..d0d0505 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/PasswordResetRequest.java @@ -0,0 +1,19 @@ +package com.lions.dev.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +public class PasswordResetRequest { + + @NotBlank(message = "L'email est obligatoire") + @Email(message = "Format d'email invalide") + private String email; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/src/main/java/com/lions/dev/resource/UsersResource.java b/src/main/java/com/lions/dev/resource/UsersResource.java index 877f66a..af6d5c8 100644 --- a/src/main/java/com/lions/dev/resource/UsersResource.java +++ b/src/main/java/com/lions/dev/resource/UsersResource.java @@ -1,5 +1,6 @@ package com.lions.dev.resource; +import com.lions.dev.dto.PasswordResetRequest; import com.lions.dev.dto.request.users.UserAuthenticateRequestDTO; import com.lions.dev.dto.request.users.UserCreateRequestDTO; import com.lions.dev.dto.response.users.UserAuthenticateResponseDTO; @@ -17,8 +18,10 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.io.File; import java.util.List; +import java.util.Map; import java.util.UUID; import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; @@ -273,4 +276,46 @@ public class UsersResource { } } + /** + * Endpoint pour demander une réinitialisation de mot de passe par email. + * + * @param request Le DTO contenant l'email de l'utilisateur. + * @return Une réponse HTTP indiquant que l'email a été envoyé (ou non, pour ne pas révéler si l'email existe). + */ + @POST + @Path("/forgot-password") + @Operation(summary = "Demander une reinitialisation de mot de passe par email", + description = "Envoie un email de reinitialisation si un compte existe avec cet email") + @APIResponse(responseCode = "200", description = "Email de reinitialisation envoye si le compte existe") + @APIResponse(responseCode = "400", description = "Email invalide") + public Response requestPasswordReset(@Valid PasswordResetRequest request) { + LOG.info("Demande de reinitialisation de mot de passe pour l'email : " + request.getEmail()); + + try { + // Rechercher l'utilisateur par email + Users user = userService.findByEmail(request.getEmail()); + + if (user != null) { + // TODO: Generer un token de reset et l'envoyer par email + // Pour l'instant, on retourne success pour ne pas reveler si l'email existe + // String resetToken = generateResetToken(); + // emailService.sendPasswordResetEmail(user.getEmail(), resetToken); + LOG.info("Utilisateur trouve, email de reinitialisation devrait etre envoye : " + request.getEmail()); + } else { + LOG.info("Aucun utilisateur trouve avec cet email (ne pas reveler) : " + request.getEmail()); + } + + // Toujours retourner 200 pour ne pas reveler si l'email existe + return Response.ok() + .entity(Map.of("message", "Si un compte existe avec cet email, un lien de reinitialisation a ete envoye")) + .build(); + } catch (Exception e) { + LOG.error("Erreur lors de la demande de reinitialisation de mot de passe", e); + // Toujours retourner 200 pour ne pas reveler si l'email existe + return Response.ok() + .entity(Map.of("message", "Si un compte existe avec cet email, un lien de reinitialisation a ete envoye")) + .build(); + } + } + } diff --git a/src/main/java/com/lions/dev/service/UsersService.java b/src/main/java/com/lions/dev/service/UsersService.java index 8999bc9..588c963 100644 --- a/src/main/java/com/lions/dev/service/UsersService.java +++ b/src/main/java/com/lions/dev/service/UsersService.java @@ -251,4 +251,16 @@ public class UsersService { System.out.println("[LOG] Utilisateur trouvé avec l'email : " + email); return userOptional.get(); } + + /** + * Recherche un utilisateur par son email (retourne null si non trouvé). + * Utilisé pour les opérations où on ne veut pas lever d'exception si l'utilisateur n'existe pas. + * + * @param email L'email de l'utilisateur à rechercher. + * @return L'utilisateur trouvé ou null si non trouvé. + */ + public Users findByEmail(String email) { + Optional userOptional = usersRepository.findByEmail(email); + return userOptional.orElse(null); + } } diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties index 9a74a10..020845c 100644 --- a/src/main/resources/application-production.properties +++ b/src/main/resources/application-production.properties @@ -8,6 +8,21 @@ # HTTP - Chemin de base de l'API # ==================================================================== # Permet d'accéder à l'API via https://api.lions.dev/afterwork +# +# IMPORTANT - Configuration Ingress requise: +# Cette application utilise quarkus.http.root-path pour être "context-aware", +# ce qui permet à Swagger UI de générer les bonnes URLs. +# L'Ingress Kubernetes DOIT préserver le chemin complet (PAS de rewrite-target). +# +# Configuration Ingress correcte: +# - path: /afterwork +# - pathType: Prefix +# - PAS d'annotation rewrite-target +# +# Pourquoi cette approche ? +# - Swagger UI nécessite que l'application connaisse son contexte +# - Les URLs générées (OpenAPI, WebSocket) sont correctes +# - Cohérent avec les applications context-aware (btpxpress, etc.) quarkus.http.root-path=/afterwork # ==================================================================== @@ -17,10 +32,13 @@ quarkus.http.root-path=/afterwork quarkus.swagger-ui.enable=true quarkus.swagger-ui.always-include=true quarkus.swagger-ui.path=/q/swagger-ui -# Configuration explicite de l'URL OpenAPI pour Swagger UI -# Avec root-path=/afterwork, l'OpenAPI spec est à /afterwork/openapi -quarkus.swagger-ui.urls.default=/afterwork/openapi +# Configuration du chemin OpenAPI (relatif au root-path) quarkus.smallrye-openapi.path=/openapi +# Configuration des serveurs OpenAPI pour que Swagger UI génère les bonnes URLs +quarkus.smallrye-openapi.servers=https://api.lions.dev/afterwork +# Configuration explicite de l'URL OpenAPI pour Swagger UI +# Essayer avec URL absolue pour forcer le bon chemin +quarkus.swagger-ui.urls.default=https://api.lions.dev/afterwork/openapi # ==================================================================== # Base de données PostgreSQL @@ -35,9 +53,18 @@ quarkus.datasource.jdbc.min-size=5 quarkus.datasource.devservices.enabled=false # ==================================================================== -# Hibernate ORM +# Flyway - Migrations SQL automatiques # ==================================================================== -quarkus.hibernate-orm.database.generation=update +quarkus.flyway.migrate-at-start=true +quarkus.flyway.locations=db/migration +quarkus.flyway.baseline-on-migrate=true +quarkus.flyway.baseline-version=1 +quarkus.flyway.validate-on-migrate=true + +# ==================================================================== +# Hibernate ORM - Mode validation (Flyway gere le schema) +# ==================================================================== +quarkus.hibernate-orm.database.generation=none quarkus.hibernate-orm.log.sql=false quarkus.hibernate-orm.sql-load-script=no-file quarkus.hibernate-orm.jdbc.statement-batch-size=20 @@ -64,6 +91,23 @@ quarkus.log.category."com.lions.dev".level=INFO quarkus.log.category."org.hibernate".level=WARN quarkus.log.category."io.quarkus".level=INFO +# ==================================================================== +# Kafka Configuration (Production) +# ==================================================================== +# Kafka est deploye dans le namespace 'kafka' du cluster Kubernetes +# Service: kafka-service.kafka.svc.cluster.local:9092 +kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS:kafka-service.kafka.svc.cluster.local:9092} + +# Configuration de resilience Kafka +mp.messaging.connector.smallrye-kafka.health-enabled=true +mp.messaging.connector.smallrye-kafka.health-readiness-enabled=true + +# Topics auto-crees par Quarkus SmallRye Kafka: +# - notifications +# - chat.messages +# - reactions +# - presence.updates + # ==================================================================== # WebSocket # ==================================================================== diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2004b19..9967b7d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -55,7 +55,7 @@ quarkus.http.limits.max-body-size=10M # ==================================================================== # Kafka Configuration (commun à tous les environnements) # ==================================================================== -kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS:localhost:9092} +kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS:kafka-service.kafka.svc.cluster.local:9092} # ==================================================================== # Kafka Topics - Outgoing (Services → Kafka) diff --git a/src/main/resources/db/migration/V1__Baseline.sql b/src/main/resources/db/migration/V1__Baseline.sql new file mode 100644 index 0000000..48f9883 --- /dev/null +++ b/src/main/resources/db/migration/V1__Baseline.sql @@ -0,0 +1,5 @@ +-- V1__Baseline.sql +-- Script de baseline pour Flyway +-- Ce script est vide car le schema initial a ete cree par Hibernate +-- Flyway utilisera ce point comme reference pour les migrations suivantes +SELECT 1;