From 2f33b0975389420da97e5c593e3e8ec6b16f631f Mon Sep 17 00:00:00 2001 From: DahoudG Date: Sun, 17 Nov 2024 22:58:38 +0000 Subject: [PATCH] Refactoring + Checkpoint --- pom.xml | 27 ++++-- src/main/docker/docker-compose.yml | 58 +++++++++++++ .../events/EventCreateResponseDTO.java | 6 +- .../events/EventReadManyByIdResponseDTO.java | 8 ++ ...riendshipReadFriendDetailsResponseDTO.java | 5 +- .../com/lions/dev/entity/events/Events.java | 5 +- .../dev/repository/FriendshipRepository.java | 64 ++++++++++---- .../lions/dev/resource/EventsResource.java | 86 ++++++++++++++++++- .../lions/dev/service/FriendshipService.java | 19 +++- src/main/resources/application.properties | 50 +++++++---- 10 files changed, 278 insertions(+), 50 deletions(-) create mode 100644 src/main/docker/docker-compose.yml diff --git a/pom.xml b/pom.xml index eee651b..cde4864 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,21 @@ + + + org.hibernate.validator + hibernate-validator + + + jakarta.el + jakarta.el-api + 5.0.0 + + + io.quarkus + quarkus-jdbc-postgresql + 3.13.0 + io.quarkus quarkus-smallrye-jwt @@ -39,7 +54,7 @@ org.springframework.security spring-security-core - 6.3.3 + 6.3.4 com.fasterxml.jackson.datatype @@ -48,7 +63,7 @@ io.quarkiverse.groovy quarkus-groovy-junit5 - 3.12.1 + 3.16.1 io.quarkus @@ -84,15 +99,11 @@ rest-assured test - - - org.hibernate.validator - hibernate-validator - + org.projectlombok lombok - 1.18.30 + 1.18.34 provided diff --git a/src/main/docker/docker-compose.yml b/src/main/docker/docker-compose.yml new file mode 100644 index 0000000..200b4ae --- /dev/null +++ b/src/main/docker/docker-compose.yml @@ -0,0 +1,58 @@ +version: '3.8' + +services: + # Service pour la base de données PostgreSQL + db: + image: postgres:13 + container_name: afterwork_db + environment: + POSTGRES_USER: ${DB_USERNAME} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: ${DB_NAME} + ports: + - "5432:5432" + networks: + - afterwork-network + volumes: + - db_data:/var/lib/postgresql/data + + # Service pour l'application Quarkus + app: + build: + context: . + dockerfile: src/main/docker/Dockerfile.jvm + container_name: afterwork-quarkus + environment: + DB_USERNAME: ${DB_USERNAME} + DB_PASSWORD: ${DB_PASSWORD} + DB_HOST: db + DB_PORT: 5432 + DB_NAME: ${DB_NAME} + JAVA_OPTS_APPEND: "-Dquarkus.http.host=0.0.0.0" + ports: + - "8080:8080" + depends_on: + - db + networks: + - afterwork-network + + # Service pour Swagger UI + swagger-ui: + image: swaggerapi/swagger-ui + container_name: afterwork-swagger-ui + environment: + SWAGGER_JSON: http://app:8080/openapi + ports: + - "8081:8080" + depends_on: + - app + networks: + - afterwork-network + +networks: + afterwork-network: + driver: bridge + +volumes: + db_data: + driver: local diff --git a/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java index 96d3d08..2ade755 100644 --- a/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java @@ -21,7 +21,9 @@ public class EventCreateResponseDTO { private String link; // Lien vers plus d'informations private String imageUrl; // URL d'une image pour l'événement private String creatorEmail; // Email du créateur de l'événement - private String status; + private String creatorFirstName; // Prénom du créateur de l'événement + private String creatorLastName; // Nom de famille du création de l'événement + private String status; // Statut de l'événement /** * Constructeur qui transforme une entité Events en DTO. @@ -39,6 +41,8 @@ public class EventCreateResponseDTO { this.link = event.getLink(); this.imageUrl = event.getImageUrl(); this.creatorEmail = event.getCreator().getEmail(); + this.creatorFirstName = event.getCreator().getPrenoms(); + this.creatorLastName = event.getCreator().getNom(); this.status = event.getStatus(); } } diff --git a/src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java index 28795b5..1795430 100644 --- a/src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java @@ -21,6 +21,10 @@ public class EventReadManyByIdResponseDTO { private String link; // Lien vers plus d'informations private String imageUrl; // URL de l'image de l'événement private String status; // Statut de l'événement + private String creatorEmail; // Email de l'utilisateur qui a créé l'événement + private String creatorFirstName; // Prénom de l'utilisateur qui a criané l'événement + private String creatorLastName; // Nom de l'utilisateur qui a criané l'événement + private String profileImageUrl; // URL de l'image de profil de l'utilisateur qui a criané l'événement /** * Constructeur qui transforme une entité Events en DTO de réponse. @@ -38,5 +42,9 @@ public class EventReadManyByIdResponseDTO { this.link = event.getLink(); this.imageUrl = event.getImageUrl(); this.status = event.getStatus(); + this.creatorEmail = event.getCreator().getEmail(); + this.creatorFirstName = event.getCreator().getPrenoms(); + this.creatorLastName = event.getCreator().getNom(); + this.profileImageUrl = event.getCreator().getProfileImageUrl(); } } diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java index e0655fd..792760e 100644 --- a/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java @@ -22,6 +22,7 @@ public class FriendshipReadFriendDetailsResponseDTO { private String friendLastName; // Nom de l'ami private String friendFirstName; // Prénom de l'ami private String friendEmail; // Email de l'ami + private String friendProfileImageUrl; private FriendshipStatus status; // Statut de la relation d'amitié private LocalDateTime createdAt; // Date de création de la relation d'amitié private LocalDateTime updatedAt; // Date de la dernière mise à jour de la relation @@ -34,19 +35,21 @@ public class FriendshipReadFriendDetailsResponseDTO { * @param friendLastName Le nom de l'ami. * @param friendFirstName Le prénom de l'ami. * @param friendEmail L'email de l'ami. + * @param friendProfileImageUrl L'URL de l'image de profil de l'ami. * @param status Le statut de la relation d'amitié. * @param createdAt La date de création de la relation. * @param updatedAt La date de la dernière mise à jour de la relation. */ public FriendshipReadFriendDetailsResponseDTO(UUID userId, UUID friendId, String friendLastName, String friendFirstName, - String friendEmail, FriendshipStatus status, + String friendEmail, String friendProfileImageUrl, FriendshipStatus status, LocalDateTime createdAt, LocalDateTime updatedAt) { this.userId = userId; this.friendId = friendId; this.friendLastName = friendLastName; this.friendFirstName = friendFirstName; this.friendEmail = friendEmail; + this.friendProfileImageUrl = friendProfileImageUrl; this.status = status; this.createdAt = createdAt; this.updatedAt = updatedAt; diff --git a/src/main/java/com/lions/dev/entity/events/Events.java b/src/main/java/com/lions/dev/entity/events/Events.java index cd1e7d1..d204562 100644 --- a/src/main/java/com/lions/dev/entity/events/Events.java +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -31,7 +31,7 @@ public class Events extends BaseEntity { @Column(name = "title", nullable = false) private String title; // Le titre de l'événement - @Column(name = "description") + @Column(name = "description",length = 1000) private String description; // La description de l'événement @Column(name = "start_date", nullable = false) @@ -55,9 +55,6 @@ public class Events extends BaseEntity { @Column(name = "status", nullable = false) private String status = "ouvert"; // Le statut de l'événement (en cours, terminé, annulé, etc.) - @Column(name = "profile_image_url") - private String profileImageUrl; // URL de la photo de profil - @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "creator_id", nullable = false) private Users creator; // L'utilisateur créateur de l'événement diff --git a/src/main/java/com/lions/dev/repository/FriendshipRepository.java b/src/main/java/com/lions/dev/repository/FriendshipRepository.java index 7661c60..7f24780 100644 --- a/src/main/java/com/lions/dev/repository/FriendshipRepository.java +++ b/src/main/java/com/lions/dev/repository/FriendshipRepository.java @@ -5,30 +5,53 @@ import com.lions.dev.entity.friends.FriendshipStatus; import com.lions.dev.entity.users.Users; import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; import jakarta.enterprise.context.ApplicationScoped; +import org.jboss.logging.Logger; + import java.util.List; import java.util.Optional; import java.util.UUID; /** * Repository pour gérer les relations d'amitié (Friendship) dans la base de données. - * Il contient des méthodes pour récupérer, ajouter, et supprimer des relations d'amitié. + * Cette classe contient des méthodes pour récupérer, ajouter, et supprimer des relations d'amitié. + * Elle est utilisée pour interagir avec la table des relations d'amitié en base de données. + * + * Elle est annotée avec @ApplicationScoped pour être gérée par le conteneur CDI de Quarkus. */ @ApplicationScoped public class FriendshipRepository implements PanacheRepositoryBase { + // Logger pour les logs de la classe + private static final Logger logger = Logger.getLogger(FriendshipRepository.class); + /** - * Trouver une relation d'amitié entre deux utilisateurs. + * Trouver une relation d'amitié entre deux utilisateurs spécifiés. + * Cette méthode recherche une relation d'amitié entre deux utilisateurs donnés. + * Elle peut être utilisée pour vérifier si une demande d'amitié existe déjà. * * @param user L'utilisateur qui envoie la demande d'amitié. * @param friend L'ami qui reçoit la demande. * @return Une Optional contenant la relation d'amitié si elle existe. */ public Optional findByUsers(Users user, Users friend) { - return find("user = ?1 and friend = ?2", user, friend).firstResultOptional(); + logger.infof("Recherche de la relation d'amitié entre les utilisateurs : %s et %s", user.getId(), friend.getId()); + + // Requête qui cherche une relation d'amitié entre deux utilisateurs spécifiques + Optional friendship = find("user = ?1 and friend = ?2", user, friend).firstResultOptional(); + + if (friendship.isPresent()) { + logger.infof("Relation d'amitié trouvée entre %s et %s", user.getId(), friend.getId()); + } else { + logger.warnf("Aucune relation d'amitié trouvée entre %s et %s", user.getId(), friend.getId()); + } + + return friendship; } /** - * Récupérer la liste des amis d'un utilisateur, c'est-à-dire toutes les relations acceptées. + * Récupérer la liste des amis d'un utilisateur avec un statut d'amitié spécifique (ACCEPTED). + * Cette méthode récupère les relations d'amitié acceptées pour un utilisateur donné, + * avec la possibilité de paginer les résultats. * * @param user L'utilisateur dont on souhaite récupérer les amis. * @param page Le numéro de la page à récupérer. @@ -36,29 +59,40 @@ public class FriendshipRepository implements PanacheRepositoryBase findFriendsByUser(Users user, int page, int size) { - System.out.println("**************************************************************" + user.getId()); - // Utiliser une requête basée sur les IDs pour éviter les duplications - return find("(user.id = ?1 OR friend.id = ?1) AND status = ?2", user.getId(), - FriendshipStatus.ACCEPTED) + logger.infof("Récupération des amis pour l'utilisateur %s, page %d, taille %d", user.getId(), page, size); + + // Utilisation d'une requête pour récupérer les relations d'amitié acceptées pour l'utilisateur spécifié + List friendships = find("(user.id = ?1 OR friend.id = ?1) AND status = ?2", user.getId(), FriendshipStatus.ACCEPTED) .page(page, size) .stream() -// .filter(friendship -> !friendship.getUser().equals(friendship.getFriend())) // Exclure les relations dupliquées -// .distinct() // Appliquer distinct sur le flux pour éviter tout doublon supplémentaire + .filter(friendship -> !friendship.getUser().equals(friendship.getFriend())) // Exclure les relations où l'utilisateur est ami avec lui-même + .distinct() // Appliquer distinct pour éviter les doublons .toList(); + + logger.infof("Nombre d'amis récupérés pour l'utilisateur %s : %d", user.getId(), friendships.size()); + return friendships; } /** * Récupérer toutes les relations d'amitié d'un utilisateur avec un statut spécifique. + * Cette méthode permet de filtrer les relations par statut (par exemple, ACCEPTED, PENDING). + * Elle est également paginée. * - * @param user L'utilisateur dont on souhaite récupérer les amitiés. - * @param status Le statut des relations d'amitié à filtrer. - * @param page Le numéro de la page. - * @param size La taille de la page. + * @param user L'utilisateur dont on souhaite récupérer les relations d'amitié. + * @param status Le statut des relations d'amitié à filtrer (ACCEPTED, PENDING, etc.). + * @param page Le numéro de la page à récupérer. + * @param size La taille de la page (nombre d'éléments). * @return Une liste paginée de relations d'amitié avec le statut spécifié. */ public List findByUserAndStatus(Users user, FriendshipStatus status, int page, int size) { - return find("(user = ?1 or friend = ?1) and status = ?2", user, status) + logger.infof("Récupération des relations d'amitié pour l'utilisateur %s avec le statut %s, page %d, taille %d", user.getId(), status, page, size); + + // Requête pour récupérer les relations avec un statut spécifique + List friendships = find("(user = ?1 OR friend = ?1) AND status = ?2", user, status) .page(page, size) .list(); + + logger.infof("Nombre de relations récupérées pour l'utilisateur %s avec le statut %s : %d", user.getId(), status, friendships.size()); + return friendships; } } diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 8d00abc..3603bc8 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -651,7 +651,6 @@ public class EventsResource { return Response.ok(responseDTOs).build(); } - @POST @Path("/{id}/favorite") @Transactional @@ -750,5 +749,90 @@ public class EventsResource { String shareLink = "https://lions.dev /events/" + eventId; return Response.ok(Map.of("shareLink", shareLink)).build(); } + + /** + * Endpoint pour fermer un événement. + * + * @param eventId L'ID de l'événement. + * @return Une réponse HTTP indiquant le succès de la fermeture. + */ + @PATCH + @Path("/{id}/close") + @Transactional + @Operation( + summary = "Fermer un événement", + description = "Ferme un événement et empêche les nouvelles participations" + ) + public Response closeEvent(@PathParam("id") UUID eventId) { + LOG.info("Tentative de fermeture de l'événement avec l'ID : " + eventId); + + // Recherche de l'événement par ID + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND) + .entity("Événement non trouvé.") + .build(); + } + + // Marquer l'événement comme fermé + event.setStatus("fermé"); // Modification du statut de l'événement + eventsRepository.persist(event); // Persister les modifications dans la base + LOG.info("Événement fermé avec succès : " + event.getTitle()); + + // Retourner une réponse HTTP 200 OK avec le DTO de l'événement fermé + return Response.ok(new EventCreateResponseDTO(event)).build(); + } + + /** + * Endpoint pour réouvrir un événement. + * + * @param eventId L'ID de l'événement à rouvrir. + * @return Une réponse HTTP indiquant le succès ou l'échec de la réouverture. + */ + @PATCH + @Path("{eventId}/reopen") + @Transactional + @Operation( + summary = "Rouvrir un événement", + description = "Rouvre un événement existant qui est actuellement fermé" + ) + public Response reopenEvent(@PathParam("eventId") UUID eventId) { + LOG.info("Tentative de réouverture de l'événement avec l'ID : " + eventId); + + // Recherche de l'événement par ID + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND) + .entity("Événement non trouvé.") + .build(); + } + + // Vérifier si l'événement est déjà ouvert + if ("ouvert".equals(event.getStatus())) { + LOG.warn("L'événement est déjà ouvert : " + eventId); + return Response.status(Response.Status.BAD_REQUEST) + .entity("L'événement est déjà ouvert.") + .build(); + } + + // Vérifier si l'événement est fermé avant de tenter la réouverture + if (!"fermé".equals(event.getStatus())) { + LOG.warn("L'événement n'est pas fermé, donc il ne peut pas être rouvert : " + eventId); + return Response.status(Response.Status.BAD_REQUEST) + .entity("L'événement n'est pas fermé et ne peut pas être rouvert.") + .build(); + } + + // Réouvrir l'événement en mettant à jour son statut + event.setStatus("ouvert"); // Changer le statut à "Ouvert" + eventsRepository.persist(event); // Persister les modifications dans la base + LOG.info("Événement rouvert avec succès : " + event.getTitle()); + + // Retourner une réponse HTTP 200 OK avec un message de succès + return Response.ok("L'événement a été réouvert avec succès.").build(); + } + } diff --git a/src/main/java/com/lions/dev/service/FriendshipService.java b/src/main/java/com/lions/dev/service/FriendshipService.java index 92fadba..ac9589f 100644 --- a/src/main/java/com/lions/dev/service/FriendshipService.java +++ b/src/main/java/com/lions/dev/service/FriendshipService.java @@ -79,14 +79,24 @@ public class FriendshipService { */ @Transactional public FriendshipCreateOneResponseDTO acceptFriendRequest(UUID friendshipId) { + // Vérification de l'ID de la demande d'amitié + if (friendshipId == null) { + logger.error(String.format("[ERROR] L'ID de la demande d'amitié est nul.")); + throw new IllegalArgumentException("L'ID de la demande d'amitié est nul."); + } + + // Rechercher l'amitié dans la base de données Friendship friendship = friendshipRepository.findById(friendshipId); + + // Si l'amitié n'est pas trouvée, lever une exception if (friendship == null) { + logger.error(String.format("[ERROR] Demande d'amitié introuvable pour l'ID: %s", friendshipId)); // Correctement formaté throw new FriendshipNotFoundException("Demande d'amitié introuvable."); } // Vérifier que la demande n'est pas déjà acceptée if (friendship.getStatus() == FriendshipStatus.ACCEPTED) { - logger.error("[ERROR] Demande d'amitié déjà acceptée."); + logger.error(String.format("[ERROR] Demande d'amitié déjà acceptée pour l'ID: %s", friendshipId)); // Correctement formaté throw new IllegalArgumentException("Demande d'amitié déjà acceptée."); } @@ -94,7 +104,10 @@ public class FriendshipService { friendship.setStatus(FriendshipStatus.ACCEPTED); friendshipRepository.persist(friendship); - logger.info("[LOG] Demande d'amitié acceptée avec succès."); + // Log de succès + logger.info(String.format("[LOG] Demande d'amitié acceptée avec succès pour l'ID: %s", friendshipId)); // Correctement formaté + + // Retourner la réponse avec les informations de la relation d'amitié return new FriendshipCreateOneResponseDTO(friendship); } @@ -175,6 +188,7 @@ public class FriendshipService { friend.getNom(), // Nom de l'ami friend.getPrenoms(), friend.getEmail(), // Email de l'ami + friend.getProfileImageUrl(), // URL de l'image de profil de l'ami friendship.getStatus(), // Statut de la relation friendship.getCreatedAt(), // Date de création de la relation friendship.getUpdatedAt() // Date de mise à jour de la relation @@ -211,6 +225,7 @@ public class FriendshipService { friend.getNom(), friend.getPrenoms(), friend.getEmail(), + friend.getProfileImageUrl(), friendship.getStatus(), friendship.getCreatedAt(), friendship.getUpdatedAt() diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6fc7375..48f0219 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,25 +1,35 @@ -# Configuration Quarkus -quarkus.http.port=8085 - # Configuration Swagger UI quarkus.swagger-ui.always-include=true quarkus.swagger-ui.path=/q/swagger-ui quarkus.smallrye-openapi.path=/openapi -# Configuration de la base de donnes -quarkus.datasource.db-kind=oracle -quarkus.datasource.jdbc.url=jdbc:oracle:thin:@localhost:1522:ORCLCDB -quarkus.datasource.username=C##AFTERWORK -quarkus.datasource.password=afterwork -quarkus.datasource.jdbc.driver=oracle.jdbc.OracleDriver -quarkus.hibernate-orm.database.generation=update -quarkus.hibernate-orm.log.sql=true -quarkus.datasource.devservices.enabled=false +# Configuration de la base de donnes PostgreSQL pour Quarkus en dveloppement +%dev.quarkus.datasource.db-kind=postgresql +%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/afterwork_db +%dev.quarkus.datasource.username=${DB_USERNAME} +%dev.quarkus.datasource.password=${DB_PASSWORD} +%dev.quarkus.datasource.jdbc.driver=org.postgresql.Driver +%dev.quarkus.hibernate-orm.database.generation=update +%dev.quarkus.hibernate-orm.log.sql=true +%dev.quarkus.datasource.devservices.enabled=false -# Niveau de logging -quarkus.log.level=INFO +# Configuration de la base de donnes PostgreSQL pour Quarkus en production +%prod.quarkus.datasource.db-kind=postgresql +%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:afterwork_db} +%prod.quarkus.datasource.username=${DB_USERNAME} +%prod.quarkus.datasource.password=${DB_PASSWORD} +%prod.quarkus.datasource.jdbc.driver=org.postgresql.Driver +%prod.quarkus.hibernate-orm.database.generation=update +%prod.quarkus.hibernate-orm.log.sql=false +%prod.quarkus.datasource.devservices.enabled=false -# Configuration la cl de signature JWT +# Niveau de logging pour Quarkus en dveloppement +%dev.quarkus.log.level=DEBUG + +# Niveau de logging pour Quarkus en production +%prod.quarkus.log.level=INFO + +# Configuration de la signature JWT # mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem # mp.jwt.verify.issuer=https://issuer.example.com # mp.jwt.token.header=Authorization @@ -28,7 +38,11 @@ quarkus.log.level=INFO # smallrye.jwt.sign.key.algorithm=RS256 # smallrye.jwt.token.lifetime=3600 -# Activer le support multipart +# Activer le support multipart pour l'upload de fichiers quarkus.http.body.uploads-directory=/tmp/uploads -quarkus.http.body.multipart.max-file-size=10M -quarkus.http.body.multipart.max-request-size=15M +# Taille maximale pour la requte multipart (en octets) +quarkus.http.body.multipart.max-request-size=10M + +# Taille maximale pour un fichier multipart (en octets) +quarkus.http.body.multipart.max-file-size=5M +