From a5743d91af8fb422a37749ecb8c69e1a83358bb9 Mon Sep 17 00:00:00 2001 From: DahoudG Date: Mon, 16 Sep 2024 19:40:48 +0000 Subject: [PATCH 1/8] Refactoring et Ajouts de nouveaux endpoints --- .../core/errors/GlobalExceptionHandler.java | 25 +++ .../exceptions/EventNotFoundException.java | 15 ++ ...estDTO.java => EventCreateRequestDTO.java} | 46 ++-- .../request/events/EventDeleteRequestDTO.java | 20 ++ .../request/events/EventReadRequestDTO.java | 20 ++ .../request/events/EventUpdateRequestDTO.java | 22 ++ ...uestDTO.java => UserCreateRequestDTO.java} | 2 +- .../request/users/UserDeleteRequestDto.java | 32 +++ ...seDTO.java => EventCreateResponseDTO.java} | 32 ++- .../events/EventDeleteResponseDTO.java | 36 +++ .../events/EventUpdateResponseDTO.java | 33 +++ .../users/UserAuthenticateResponseDTO.java | 14 +- ...nseDTO.java => UserCreateResponseDTO.java} | 7 +- .../response/users/UserDeleteResponseDto.java | 38 ++++ .../com/lions/dev/entity/events/Events.java | 35 ++- .../com/lions/dev/entity/users/Users.java | 2 - .../dev/exception/EventNotFoundException.java | 13 +- .../dev/repository/EventsRepository.java | 65 +----- .../lions/dev/repository/UsersRepository.java | 1 - .../lions/dev/resource/EventsResource.java | 208 +++++++++++++++--- .../com/lions/dev/resource/UsersResource.java | 32 ++- .../com/lions/dev/service/EventService.java | 33 ++- .../com/lions/dev/service/UserService.java | 17 +- 23 files changed, 557 insertions(+), 191 deletions(-) create mode 100644 src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java create mode 100644 src/main/java/com/lions/dev/core/errors/exceptions/EventNotFoundException.java rename src/main/java/com/lions/dev/dto/request/events/{EventRequestDTO.java => EventCreateRequestDTO.java} (59%) create mode 100644 src/main/java/com/lions/dev/dto/request/events/EventDeleteRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java rename src/main/java/com/lions/dev/dto/request/users/{UserRequestDTO.java => UserCreateRequestDTO.java} (97%) create mode 100644 src/main/java/com/lions/dev/dto/request/users/UserDeleteRequestDto.java rename src/main/java/com/lions/dev/dto/response/events/{EventResponseDTO.java => EventCreateResponseDTO.java} (60%) create mode 100644 src/main/java/com/lions/dev/dto/response/events/EventDeleteResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/events/EventUpdateResponseDTO.java rename src/main/java/com/lions/dev/dto/response/users/{UserResponseDTO.java => UserCreateResponseDTO.java} (77%) create mode 100644 src/main/java/com/lions/dev/dto/response/users/UserDeleteResponseDto.java diff --git a/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java new file mode 100644 index 0000000..4bdcf11 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java @@ -0,0 +1,25 @@ +package com.lions.dev.core.errors; + +import com.lions.dev.core.errors.exceptions.EventNotFoundException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +/** + * Gestionnaire global des exceptions pour mapper les exceptions à des réponses HTTP appropriées. + */ +@Provider +public class GlobalExceptionHandler implements ExceptionMapper { + + @Override + public Response toResponse(Throwable exception) { + if (exception instanceof EventNotFoundException) { + return Response.status(Response.Status.NOT_FOUND) + .entity(exception.getMessage()) + .build(); + } + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Une erreur interne est survenue.") + .build(); + } +} diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/EventNotFoundException.java b/src/main/java/com/lions/dev/core/errors/exceptions/EventNotFoundException.java new file mode 100644 index 0000000..4fb83a5 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/exceptions/EventNotFoundException.java @@ -0,0 +1,15 @@ +package com.lions.dev.core.errors.exceptions; + +/** + * Exception lancée lorsque l'événement n'est pas trouvé. + */ +public class EventNotFoundException extends RuntimeException { + + public EventNotFoundException(String message) { + super(message); + } + + public EventNotFoundException(java.util.UUID eventId) { + super("L'événement avec l'ID " + eventId + " n'a pas été trouvé."); + } +} diff --git a/src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java similarity index 59% rename from src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java rename to src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java index fecb22a..c411a59 100644 --- a/src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java @@ -8,53 +8,33 @@ import java.time.LocalDateTime; /** * DTO pour la création d'un événement. * Ce DTO est utilisé dans les requêtes de création d'événements, envoyant les informations - * nécessaires comme le titre, les dates et le créateur. + * nécessaires comme le titre, les dates, la description, le créateur, et d'autres attributs. */ -public class EventRequestDTO { +@lombok.Getter +@lombok.Setter +public class EventCreateRequestDTO { @NotNull(message = "Le titre de l'événement est obligatoire.") @Size(min = 3, max = 100, message = "Le titre doit comporter entre 3 et 100 caractères.") private String title; // Titre de l'événement + private String description; // Description de l'événement + @NotNull(message = "La date de début est obligatoire.") private LocalDateTime startDate; // Date de début de l'événement @NotNull(message = "La date de fin est obligatoire.") private LocalDateTime endDate; // Date de fin de l'événement + private String location; // Lieu de l'événement + private String category; // Catégorie de l'événement + private String link; // Lien d'information supplémentaire + private String imageUrl; // URL de l'image associée à l'événement + @NotNull(message = "Le créateur de l'événement est obligatoire.") private Users creator; // Utilisateur créateur de l'événement - // Getters et setters - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public LocalDateTime getStartDate() { - return startDate; - } - - public void setStartDate(LocalDateTime startDate) { - this.startDate = startDate; - } - - public LocalDateTime getEndDate() { - return endDate; - } - - public void setEndDate(LocalDateTime endDate) { - this.endDate = endDate; - } - - public Users getCreator() { - return creator; - } - - public void setCreator(Users creator) { - this.creator = creator; + public EventCreateRequestDTO() { + System.out.println("[LOG] DTO de requête de création d'événement initialisé."); } } diff --git a/src/main/java/com/lions/dev/dto/request/events/EventDeleteRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventDeleteRequestDTO.java new file mode 100644 index 0000000..57c59c7 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/events/EventDeleteRequestDTO.java @@ -0,0 +1,20 @@ +package com.lions.dev.dto.request.events; + +import jakarta.validation.constraints.NotNull; +import java.util.UUID; + +/** + * DTO pour la suppression d'un événement. + * Ce DTO est utilisé pour capturer l'ID d'un événement à supprimer. + */ +@lombok.Getter +@lombok.Setter +public class EventDeleteRequestDTO { + + @NotNull(message = "L'ID de l'événement est obligatoire.") + private UUID eventId; // ID de l'événement à supprimer + + public EventDeleteRequestDTO() { + System.out.println("[LOG] DTO de requête de suppression d'événement initialisé."); + } +} diff --git a/src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java new file mode 100644 index 0000000..46c5983 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java @@ -0,0 +1,20 @@ +package com.lions.dev.dto.request.events; + +import jakarta.validation.constraints.NotNull; +import java.util.UUID; + +/** + * DTO pour lire un événement par son ID. + * Ce DTO est utilisé dans les requêtes pour récupérer les informations d'un événement spécifique. + */ +@lombok.Getter +@lombok.Setter +public class EventReadRequestDTO { + + @NotNull(message = "L'ID de l'événement est obligatoire.") + private UUID eventId; // ID de l'événement à lire + + public EventReadRequestDTO() { + System.out.println("[LOG] DTO de requête de lecture d'événement initialisé."); + } +} diff --git a/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java new file mode 100644 index 0000000..137a4c1 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java @@ -0,0 +1,22 @@ +package com.lions.dev.dto.request.events; + +import java.time.LocalDateTime; +import lombok.Getter; +import lombok.Setter; + +/** + * DTO pour la mise à jour d'un événement. + * Ce DTO est utilisé dans les requêtes de mise à jour des événements. + */ +@Getter +@Setter +public class EventUpdateRequestDTO { + private String title; + private String description; + private LocalDateTime startDate; + private LocalDateTime endDate; + private String location; + private String category; + private String link; + private String imageUrl; +} diff --git a/src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java b/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java similarity index 97% rename from src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java rename to src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java index 9fd32d2..d70ca3e 100644 --- a/src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java @@ -13,7 +13,7 @@ import lombok.Setter; */ @Getter @Setter -public class UserRequestDTO { +public class UserCreateRequestDTO { @NotNull(message = "Le nom est obligatoire.") @Size(min = 1, max = 100, message = "Le nom doit comporter entre 1 et 100 caractères.") diff --git a/src/main/java/com/lions/dev/dto/request/users/UserDeleteRequestDto.java b/src/main/java/com/lions/dev/dto/request/users/UserDeleteRequestDto.java new file mode 100644 index 0000000..5f4305b --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/users/UserDeleteRequestDto.java @@ -0,0 +1,32 @@ +package com.lions.dev.dto.request.users; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * DTO pour la requête de suppression d'un utilisateur. + * Utilisé pour encapsuler l'ID de l'utilisateur à supprimer. + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserDeleteRequestDto { + + private static final Logger logger = LoggerFactory.getLogger(UserDeleteRequestDto.class); + + /** + * Identifiant unique de l'utilisateur à supprimer. + */ + private UUID userId; + + // Méthode pour loguer les détails de la requête de suppression + public void logRequestDetails() { + logger.info("Demande de suppression pour l'utilisateur avec l'ID : {}", userId); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java similarity index 60% rename from src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java rename to src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java index c88338a..3a7ed79 100644 --- a/src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/events/EventCreateResponseDTO.java @@ -8,11 +8,17 @@ import java.time.LocalDateTime; * Ce DTO est utilisé pour structurer les données retournées dans les réponses * après les opérations sur les événements (création, récupération). */ -public class EventResponseDTO { +@lombok.Getter +public class EventCreateResponseDTO { private String title; // Titre de l'événement + private String description; // Description de l'événement private LocalDateTime startDate; // Date de début de l'événement private LocalDateTime endDate; // Date de fin de l'événement + private String location; // Lieu de l'événement + private String category; // Catégorie de l'événement + 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 /** @@ -20,27 +26,15 @@ public class EventResponseDTO { * * @param event L'événement à convertir en DTO. */ - public EventResponseDTO(Events event) { + public EventCreateResponseDTO(Events event) { this.title = event.getTitle(); + this.description = event.getDescription(); this.startDate = event.getStartDate(); this.endDate = event.getEndDate(); + this.location = event.getLocation(); + this.category = event.getCategory(); + this.link = event.getLink(); + this.imageUrl = event.getImageUrl(); this.creatorEmail = event.getCreator().getEmail(); } - - // Getters - public String getTitle() { - return title; - } - - public LocalDateTime getStartDate() { - return startDate; - } - - public LocalDateTime getEndDate() { - return endDate; - } - - public String getCreatorEmail() { - return creatorEmail; - } } diff --git a/src/main/java/com/lions/dev/dto/response/events/EventDeleteResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventDeleteResponseDTO.java new file mode 100644 index 0000000..4760f95 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/events/EventDeleteResponseDTO.java @@ -0,0 +1,36 @@ +package com.lions.dev.dto.response.events; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * DTO pour la réponse après la tentative de suppression d'un événement. + * Indique si la suppression a réussi ou échoué. + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class EventDeleteResponseDTO { + + private static final Logger logger = LoggerFactory.getLogger(EventDeleteResponseDTO.class); + + /** + * Statut indiquant si la suppression a réussi ou échoué. + */ + private boolean success; + + /** + * Message décrivant le résultat de l'opération. + */ + private String message; + + // Méthode pour loguer les détails de la réponse + public void logResponseDetails() { + logger.info("[LOG] Suppression d'événement - Succès : {}, Message : {}", success, message); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/events/EventUpdateResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventUpdateResponseDTO.java new file mode 100644 index 0000000..39bd55c --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/events/EventUpdateResponseDTO.java @@ -0,0 +1,33 @@ +package com.lions.dev.dto.response.events; + +import com.lions.dev.entity.events.Events; +import java.time.LocalDateTime; +import lombok.Getter; + +/** + * DTO pour renvoyer les informations après la mise à jour d'un événement. + */ +@Getter +public class EventUpdateResponseDTO { + private String title; + private String description; + private LocalDateTime startDate; + private LocalDateTime endDate; + private String location; + private String category; + private String link; + private String imageUrl; + private String creatorEmail; + + public EventUpdateResponseDTO(Events event) { + this.title = event.getTitle(); + this.description = event.getDescription(); + this.startDate = event.getStartDate(); + this.endDate = event.getEndDate(); + this.location = event.getLocation(); + this.category = event.getCategory(); + this.link = event.getLink(); + this.imageUrl = event.getImageUrl(); + this.creatorEmail = event.getCreator().getEmail(); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/users/UserAuthenticateResponseDTO.java b/src/main/java/com/lions/dev/dto/response/users/UserAuthenticateResponseDTO.java index 71bb156..3443103 100644 --- a/src/main/java/com/lions/dev/dto/response/users/UserAuthenticateResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/users/UserAuthenticateResponseDTO.java @@ -20,12 +20,6 @@ public class UserAuthenticateResponseDTO { private static final Logger logger = LoggerFactory.getLogger(UserAuthenticateResponseDTO.class); - /** - * Jeton JWT généré après une authentification réussie. - * Il doit être utilisé pour toutes les communications sécurisées avec l'API. - */ - // private String token; - /** * Identifiant unique de l'utilisateur authentifié. */ @@ -55,11 +49,13 @@ public class UserAuthenticateResponseDTO { * Log de création de l'objet DTO. */ static { - logger.info("UserAuthenticateResponseDTO - DTO pour la réponse d'authentification initialisé"); + logger.info("[LOG] UserAuthenticateResponseDTO - DTO pour la réponse d'authentification initialisé"); } - // Méthode personnalisée pour loguer les détails de la réponse + /** + * Méthode personnalisée pour loguer les détails de la réponse. + */ public void logResponseDetails() { - logger.info("Réponse d'authentification - Utilisateur: {}, {}, Email: {}, Rôle: {}, ID: {}, Token généré", prenoms, nom, email, role, userId); + logger.info("[LOG] Réponse d'authentification - Utilisateur: {}, {}, Email: {}, Rôle: {}, ID: {}", prenoms, nom, email, role, userId); } } diff --git a/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java b/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java similarity index 77% rename from src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java rename to src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java index 394b9b1..fa47a31 100644 --- a/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java @@ -10,9 +10,9 @@ import lombok.Getter; * après les opérations sur les utilisateurs (création, récupération). */ @Getter -public class UserResponseDTO { +public class UserCreateResponseDTO { - private UUID uuid; + private UUID uuid; // Identifiant unique de l'utilisateur private String nom; // Nom de l'utilisateur private String prenoms; // Prénoms de l'utilisateur private String email; // Email de l'utilisateur @@ -22,10 +22,11 @@ public class UserResponseDTO { * * @param user L'utilisateur à convertir en DTO. */ - public UserResponseDTO(Users user) { + public UserCreateResponseDTO(Users user) { this.uuid = user.getId(); this.nom = user.getNom(); this.prenoms = user.getPrenoms(); this.email = user.getEmail(); + System.out.println("[LOG] DTO créé pour l'utilisateur : " + this.email); } } diff --git a/src/main/java/com/lions/dev/dto/response/users/UserDeleteResponseDto.java b/src/main/java/com/lions/dev/dto/response/users/UserDeleteResponseDto.java new file mode 100644 index 0000000..c7a360e --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/users/UserDeleteResponseDto.java @@ -0,0 +1,38 @@ +package com.lions.dev.dto.response.users; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * DTO pour la réponse après la tentative de suppression d'un utilisateur. + * Indique si la suppression a réussi ou échoué. + */ +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserDeleteResponseDto { + + private static final Logger logger = LoggerFactory.getLogger(UserDeleteResponseDto.class); + + /** + * Statut indiquant si la suppression a réussi ou échoué. + */ + private boolean success; + + /** + * Message décrivant le résultat de l'opération. + */ + private String message; + + /** + * Méthode pour loguer les détails de la réponse. + */ + public void logResponseDetails() { + logger.info("[LOG] Suppression d'utilisateur - Succès : {}, Message : {}", success, message); + } +} 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 23276b4..c50e437 100644 --- a/src/main/java/com/lions/dev/entity/events/Events.java +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -14,9 +14,8 @@ import java.util.Set; /** * Entité représentant un événement dans le système AfterWork. - * Chaque événement possède un titre, une date de début, une date de fin, un créateur, - * et des participants. - * + * Chaque événement possède un titre, une description, une date de début, une date de fin, + * un créateur, une catégorie, un lieu, une URL d'image, et des participants. * Tous les logs et commentaires nécessaires pour la traçabilité et la documentation sont inclus. */ @Entity @@ -27,17 +26,33 @@ import java.util.Set; @ToString public class Events extends BaseEntity { - // Attributs de l'entité événement - @Column(name = "title", nullable = false) private String title; // Le titre de l'événement + @Column(name = "description") + private String description; // La description de l'événement + @Column(name = "start_date", nullable = false) private LocalDateTime startDate; // La date de début de l'événement @Column(name = "end_date", nullable = false) private LocalDateTime endDate; // La date de fin de l'événement + @Column(name = "location") + private String location; // Le lieu de l'événement + + @Column(name = "category") + private String category; // La catégorie de l'événement + + @Column(name = "link") + private String link; // Un lien vers plus d'informations sur l'événement + + @Column(name = "image_url") + private String imageUrl; // URL d'une image associée à l'événement + + @Column(name = "status", nullable = false) + private String status = "en cours"; // Le statut de l'événement (en cours, terminé, annulé, etc.) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "creator_id", nullable = false) private Users creator; // L'utilisateur créateur de l'événement @@ -50,6 +65,8 @@ public class Events extends BaseEntity { ) private Set participants = new HashSet<>(); // Les participants à l'événement + // Méthodes + /** * Ajoute un utilisateur en tant que participant à l'événement. * @@ -80,4 +97,12 @@ public class Events extends BaseEntity { System.out.println("[LOG] Nombre de participants à l'événement : " + this.title + " - " + count); return count; } + + /** + * Ferme l'événement en changeant son statut. + */ + public void setClosed(boolean closed) { + this.status = closed ? "fermé" : "en cours"; + System.out.println("[LOG] Statut de l'événement mis à jour : " + this.title + " - " + this.status); + } } diff --git a/src/main/java/com/lions/dev/entity/users/Users.java b/src/main/java/com/lions/dev/entity/users/Users.java index 465823a..06435b7 100644 --- a/src/main/java/com/lions/dev/entity/users/Users.java +++ b/src/main/java/com/lions/dev/entity/users/Users.java @@ -23,8 +23,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @ToString public class Users extends BaseEntity { - // Attributs de l'entité utilisateur - @Column(name = "nom", nullable = false, length = 100) private String nom; // Le nom de l'utilisateur diff --git a/src/main/java/com/lions/dev/exception/EventNotFoundException.java b/src/main/java/com/lions/dev/exception/EventNotFoundException.java index cf0b026..e310b71 100644 --- a/src/main/java/com/lions/dev/exception/EventNotFoundException.java +++ b/src/main/java/com/lions/dev/exception/EventNotFoundException.java @@ -2,6 +2,7 @@ package com.lions.dev.exception; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; +import java.util.UUID; /** * Exception levée lorsque l'événement demandé n'est pas trouvé dans la base de données. @@ -10,12 +11,12 @@ import jakarta.ws.rs.core.Response; public class EventNotFoundException extends WebApplicationException { /** - * Constructeur qui prend un message d'erreur à afficher lorsque l'exception est levée. + * Constructeur qui prend un UUID et convertit l'UUID en message détaillant l'erreur. * - * @param message Le message détaillant l'erreur. + * @param eventId L'UUID de l'événement qui n'a pas été trouvé. */ - public EventNotFoundException(String message) { - super(message, Response.Status.NOT_FOUND); - System.out.println("[ERROR] Événement non trouvé : " + message); + public EventNotFoundException(UUID eventId) { + super("Événement non trouvé avec l'ID : " + eventId.toString(), Response.Status.NOT_FOUND); + System.out.println("[ERROR] Événement non trouvé avec l'ID : " + eventId.toString()); } -} \ No newline at end of file +} diff --git a/src/main/java/com/lions/dev/repository/EventsRepository.java b/src/main/java/com/lions/dev/repository/EventsRepository.java index 843d335..146f988 100644 --- a/src/main/java/com/lions/dev/repository/EventsRepository.java +++ b/src/main/java/com/lions/dev/repository/EventsRepository.java @@ -3,79 +3,28 @@ package com.lions.dev.repository; import com.lions.dev.entity.events.Events; import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; import jakarta.enterprise.context.ApplicationScoped; - import java.time.LocalDateTime; import java.util.List; -import java.util.Optional; import java.util.UUID; /** * Repository pour l'entité Events. - * Ce repository gère les opérations de base (CRUD) sur les événements ainsi que des méthodes de filtrage personnalisées. - * - * Utilisation de Panache pour simplifier les opérations sur la base de données. + * Ce repository gère les opérations de base (CRUD) sur les événements et inclut + * des méthodes personnalisées comme la récupération des événements après une certaine date. */ @ApplicationScoped public class EventsRepository implements PanacheRepositoryBase { /** - * Recherche un événement par son titre. + * Récupère tous les événements après une date donnée. * - * @param title Le titre de l'événement à rechercher. - * @return Un Optional contenant l'événement s'il est trouvé, sinon un Optional vide. - */ - public Optional findByTitle(String title) { - System.out.println("[LOG] Recherche de l'événement avec le titre : " + title); - Events event = find("title", title).firstResult(); - if (event != null) { - System.out.println("[LOG] Événement trouvé : " + event.getTitle()); - } else { - System.out.println("[LOG] Aucun événement trouvé avec le titre : " + title); - } - return Optional.ofNullable(event); - } - - /** - * Récupère tous les événements créés par un utilisateur spécifique. - * - * @param userId L'ID de l'utilisateur créateur des événements. - * @return Une liste d'événements créés par l'utilisateur. - */ - public List findByCreator(UUID userId) { - System.out.println("[LOG] Récupération des événements créés par l'utilisateur avec l'ID : " + userId); - List events = list("creator.id", userId); - System.out.println("[LOG] Nombre d'événements trouvés pour l'utilisateur : " + events.size()); - return events; - } - - /** - * Supprime un événement par son identifiant UUID. - * - * @param id L'UUID de l'événement à supprimer. - * @return true si l'événement a été supprimé, sinon false. - */ - public boolean deleteById(UUID id) { - System.out.println("[LOG] Suppression de l'événement avec l'ID : " + id); - long deletedCount = delete("id", id); // Utiliser long pour récupérer le nombre d'enregistrements supprimés - boolean deleted = deletedCount > 0; // Convertir en boolean - if (deleted) { - System.out.println("[LOG] Événement avec l'ID " + id + " supprimé avec succès."); - } else { - System.out.println("[LOG] Aucune suppression, événement avec l'ID " + id + " introuvable."); - } - return deleted; - } - - /** - * Récupère une liste d'événements avec filtrage par date de début. - * - * @param startDate La date de début à partir de laquelle rechercher les événements. - * @return Une liste d'événements filtrés. + * @param startDate La date de début de filtre. + * @return Une liste d'événements après cette date. */ public List findEventsAfterDate(LocalDateTime startDate) { System.out.println("[LOG] Récupération des événements après la date : " + startDate); - List events = list("startDate >= ?1", startDate); - System.out.println("[LOG] Nombre d'événements trouvés après la date : " + startDate + " : " + events.size()); + List events = list("startDate > ?1", startDate); + System.out.println("[LOG] Nombre d'événements trouvés après la date " + startDate + " : " + events.size()); return events; } } diff --git a/src/main/java/com/lions/dev/repository/UsersRepository.java b/src/main/java/com/lions/dev/repository/UsersRepository.java index 63046e1..17a143d 100644 --- a/src/main/java/com/lions/dev/repository/UsersRepository.java +++ b/src/main/java/com/lions/dev/repository/UsersRepository.java @@ -63,5 +63,4 @@ public class UsersRepository implements PanacheRepositoryBase { } return deleted; } - } diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 0890d05..ff4e893 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -1,10 +1,13 @@ package com.lions.dev.resource; +import com.lions.dev.dto.response.events.EventUpdateResponseDTO; +import com.lions.dev.dto.request.events.EventUpdateRequestDTO; +import com.lions.dev.entity.users.Users; +import com.lions.dev.dto.request.events.EventCreateRequestDTO; +import com.lions.dev.dto.response.events.EventCreateResponseDTO; import com.lions.dev.entity.events.Events; import com.lions.dev.repository.EventsRepository; -import com.lions.dev.dto.request.events.EventRequestDTO; -import com.lions.dev.dto.response.events.EventResponseDTO; -import com.lions.dev.exception.EventNotFoundException; +import com.lions.dev.repository.UsersRepository; // Ajout du UsersRepository pour gérer les participants import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.*; @@ -31,30 +34,38 @@ public class EventsResource { @Inject EventsRepository eventsRepository; + @Inject + UsersRepository usersRepository; // Ajout pour la gestion des participants + private static final Logger LOG = Logger.getLogger(EventsResource.class); /** * Endpoint pour créer un nouvel événement. * - * @param eventRequestDTO Le DTO contenant les informations de l'événement à créer. + * @param eventCreateRequestDTO Le DTO contenant les informations de l'événement à créer. * @return Une réponse HTTP contenant l'événement créé ou un message d'erreur. */ @POST @Transactional @Operation(summary = "Créer un nouvel événement", description = "Crée un nouvel événement et retourne ses détails") - public Response createEvent(EventRequestDTO eventRequestDTO) { - LOG.info("Tentative de création d'un nouvel événement : " + eventRequestDTO.getTitle()); + public Response createEvent(EventCreateRequestDTO eventCreateRequestDTO) { + LOG.info("[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); Events event = new Events(); - event.setTitle(eventRequestDTO.getTitle()); - event.setStartDate(eventRequestDTO.getStartDate()); - event.setEndDate(eventRequestDTO.getEndDate()); - event.setCreator(eventRequestDTO.getCreator()); // Créateur de l'événement + event.setTitle(eventCreateRequestDTO.getTitle()); + event.setStartDate(eventCreateRequestDTO.getStartDate()); + event.setEndDate(eventCreateRequestDTO.getEndDate()); + event.setDescription(eventCreateRequestDTO.getDescription()); + event.setLocation(eventCreateRequestDTO.getLocation()); + event.setCategory(eventCreateRequestDTO.getCategory()); + event.setLink(eventCreateRequestDTO.getLink()); + event.setImageUrl(eventCreateRequestDTO.getImageUrl()); + event.setCreator(eventCreateRequestDTO.getCreator()); eventsRepository.persist(event); - LOG.info("Événement créé avec succès : " + event.getTitle()); + LOG.info("[LOG] Événement créé avec succès : " + event.getTitle()); - EventResponseDTO responseDTO = new EventResponseDTO(event); + EventCreateResponseDTO responseDTO = new EventCreateResponseDTO(event); return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } @@ -68,17 +79,16 @@ public class EventsResource { @Path("/{id}") @Operation(summary = "Récupérer un événement par ID", description = "Retourne les détails de l'événement demandé") public Response getEventById(@PathParam("id") UUID id) { - LOG.info("Récupération de l'événement avec l'ID : " + id); + LOG.info("[LOG] Récupération de l'événement avec l'ID : " + id); Events event = eventsRepository.findById(id); if (event == null) { - LOG.warn("Événement non trouvé avec l'ID : " + id); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement non trouvé.").build(); + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } - EventResponseDTO responseDTO = new EventResponseDTO(event); - LOG.info("Événement trouvé : " + event.getTitle()); + EventCreateResponseDTO responseDTO = new EventCreateResponseDTO(event); + LOG.info("[LOG] Événement trouvé : " + event.getTitle()); return Response.ok(responseDTO).build(); } @@ -92,17 +102,16 @@ public class EventsResource { @Path("/after-date") @Operation(summary = "Récupérer les événements après une date", description = "Retourne les événements après une date donnée") public Response getEventsAfterDate(@QueryParam("startDate") LocalDateTime startDate) { - LOG.info("Récupération des événements après la date : " + startDate); + LOG.info("[LOG] Récupération des événements après la date : " + startDate); List events = eventsRepository.findEventsAfterDate(startDate); if (events.isEmpty()) { - LOG.warn("Aucun événement trouvé après la date : " + startDate); - return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé après cette date.").build(); + LOG.warn("[LOG] Aucun événement trouvé après la date : " + startDate); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé après cette date.").build(); } - List responseDTOs = events.stream().map(EventResponseDTO::new).toList(); - LOG.info("Nombre d'événements trouvés après la date : " + events.size()); + List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + LOG.info("[LOG] Nombre d'événements trouvés après la date : " + events.size()); return Response.ok(responseDTOs).build(); } @@ -126,7 +135,156 @@ public class EventsResource { } else { LOG.warn("Échec de la suppression : événement introuvable avec l'ID : " + id); return Response.status(Response.Status.NOT_FOUND) - .entity("Événement non trouvé.").build(); + .entity("Événement non trouvé.").build(); } } + + /** + * Endpoint pour ajouter un participant à un événement. + * + * @param eventId L'ID de l'événement. + * @param user L'utilisateur à ajouter comme participant. + * @return Une réponse HTTP indiquant le succès de l'ajout. + */ + @POST + @Path("/{id}/participants") + @Transactional + @Operation(summary = "Ajouter un participant à un événement", description = "Ajoute un utilisateur à un événement") + public Response addParticipant(@PathParam("id") UUID eventId, Users user) { + LOG.info("Ajout d'un participant à l'événement : " + eventId); + 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(); + } + + event.addParticipant(user); + eventsRepository.persist(event); + LOG.info("Participant ajouté avec succès à l'événement : " + event.getTitle()); + return Response.ok(new EventCreateResponseDTO(event)).build(); + } + + /** + * Endpoint pour retirer un participant d'un événement. + * + * @param eventId L'ID de l'événement. + * @param userId L'ID de l'utilisateur à retirer. + * @return Une réponse HTTP indiquant le succès du retrait. + */ + @DELETE + @Path("/{id}/participants/{userId}") + @Transactional + @Operation(summary = "Retirer un participant d'un événement", description = "Supprime un utilisateur de la liste des participants d'un événement") + public Response removeParticipant(@PathParam("id") UUID eventId, @PathParam("userId") UUID userId) { + LOG.info("Retrait d'un participant de l'événement : " + eventId); + 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(); + } + + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND) + .entity("Utilisateur non trouvé.").build(); + } + + event.removeParticipant(user); + eventsRepository.persist(event); + LOG.info("Participant retiré avec succès de l'événement : " + event.getTitle()); + return Response.noContent().build(); + } + + /** + * Endpoint pour obtenir le nombre de participants à un événement. + * + * @param eventId L'ID de l'événement. + * @return Le nombre de participants. + */ + @GET + @Path("/{id}/participants/count") + @Operation(summary = "Obtenir le nombre de participants à un événement", description = "Retourne le nombre total de participants à un événement") + public Response getNumberOfParticipants(@PathParam("id") UUID eventId) { + LOG.info("Récupération du nombre de participants pour l'événement : " + eventId); + 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(); + } + + int participantCount = event.getNumberOfParticipants(); + LOG.info("Nombre de participants pour l'événement : " + participantCount); + return Response.ok(participantCount).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. + */ + @POST + @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); + 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(); + } + + event.setClosed(true); // Marquer l'événement comme fermé + eventsRepository.persist(event); + LOG.info("Événement fermé avec succès : " + event.getTitle()); + return Response.ok(new EventCreateResponseDTO(event)).build(); + } + + /** + * Endpoint pour mettre à jour un événement. + * + * @param id L'ID de l'événement. + * @param eventUpdateRequestDTO Le DTO de la requête de mise à jour. + * @return Une réponse HTTP indiquant la mise à jour. + */ + @PUT + @Path("/{id}") + @Transactional + @Operation(summary = "Mettre à jour un événement", description = "Modifie un événement existant") + public Response updateEvent(@PathParam("id") UUID id, EventUpdateRequestDTO eventUpdateRequestDTO) { + LOG.info("[LOG] Tentative de mise à jour de l'événement avec l'ID : " + id); + + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + // Mise à jour des attributs de l'événement + event.setTitle(eventUpdateRequestDTO.getTitle()); + event.setStartDate(eventUpdateRequestDTO.getStartDate()); + event.setEndDate(eventUpdateRequestDTO.getEndDate()); + event.setDescription(eventUpdateRequestDTO.getDescription()); + event.setLocation(eventUpdateRequestDTO.getLocation()); + event.setCategory(eventUpdateRequestDTO.getCategory()); + event.setLink(eventUpdateRequestDTO.getLink()); + event.setImageUrl(eventUpdateRequestDTO.getImageUrl()); + + eventsRepository.persist(event); + LOG.info("[LOG] Événement mis à jour avec succès : " + event.getTitle()); + + EventUpdateResponseDTO responseDTO = new EventUpdateResponseDTO(event); + return Response.ok(responseDTO).build(); + } + } diff --git a/src/main/java/com/lions/dev/resource/UsersResource.java b/src/main/java/com/lions/dev/resource/UsersResource.java index 408e637..836788c 100644 --- a/src/main/java/com/lions/dev/resource/UsersResource.java +++ b/src/main/java/com/lions/dev/resource/UsersResource.java @@ -1,9 +1,8 @@ package com.lions.dev.resource; import com.lions.dev.dto.request.users.UserAuthenticateRequestDTO; -import com.lions.dev.dto.request.users.UserRequestDTO; import com.lions.dev.dto.response.users.UserAuthenticateResponseDTO; -import com.lions.dev.dto.response.users.UserResponseDTO; +import com.lions.dev.dto.response.users.UserDeleteResponseDto; import com.lions.dev.entity.users.Users; import com.lions.dev.service.UserService; import jakarta.inject.Inject; @@ -34,7 +33,7 @@ public class UsersResource { /** * Endpoint pour créer un nouvel utilisateur. * - * @param userRequestDTO Le DTO contenant les informations de l'utilisateur à créer. + * @param userCreateRequestDTO Le DTO contenant les informations de l'utilisateur à créer. * @return Une réponse HTTP contenant l'utilisateur créé ou un message d'erreur. */ @POST @@ -42,15 +41,17 @@ public class UsersResource { @Operation( summary = "Créer un nouvel utilisateur", description = "Crée un nouvel utilisateur et retourne les détails") - public Response createUser(UserRequestDTO userRequestDTO) { + public Response createUser( + com.lions.dev.dto.request.users.UserCreateRequestDTO userCreateRequestDTO) { LOG.info( "Tentative de création d'un nouvel utilisateur avec l'email : " - + userRequestDTO.getEmail()); + + userCreateRequestDTO.getEmail()); // Utilisation de UserService pour créer l'utilisateur - Users user = userService.createUser(userRequestDTO); + Users user = userService.createUser(userCreateRequestDTO); - UserResponseDTO responseDTO = new UserResponseDTO(user); + com.lions.dev.dto.response.users.UserCreateResponseDTO + responseDTO = new com.lions.dev.dto.response.users.UserCreateResponseDTO(user); return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } @@ -104,7 +105,8 @@ public class UsersResource { // Utilisation de UserService pour récupérer l'utilisateur Users user = userService.getUserById(id); - UserResponseDTO responseDTO = new UserResponseDTO(user); + com.lions.dev.dto.response.users.UserCreateResponseDTO + responseDTO = new com.lions.dev.dto.response.users.UserCreateResponseDTO(user); LOG.info("Utilisateur trouvé : " + user.getEmail()); return Response.ok(responseDTO).build(); } @@ -113,7 +115,7 @@ public class UsersResource { * Endpoint pour supprimer un utilisateur par ID. * * @param id L'ID de l'utilisateur à supprimer. - * @return Une réponse HTTP indiquant le succès ou l'échec de la suppression. + * @return Une réponse HTTP avec le statut de suppression. */ @DELETE @Path("/{id}") @@ -127,12 +129,20 @@ public class UsersResource { // Utilisation de UserService pour supprimer l'utilisateur boolean deleted = userService.deleteUser(id); + UserDeleteResponseDto responseDTO = new UserDeleteResponseDto(); if (deleted) { LOG.info("Utilisateur supprimé avec succès."); - return Response.noContent().build(); + responseDTO.setSuccess(true); + responseDTO.setMessage("Utilisateur supprimé avec succès."); + responseDTO.logResponseDetails(); + return Response.ok(responseDTO).build(); } else { LOG.warn("Échec de la suppression : utilisateur introuvable avec l'ID : " + id); - return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + responseDTO.setSuccess(false); + responseDTO.setMessage("Utilisateur non trouvé."); + responseDTO.logResponseDetails(); + return Response.status(Response.Status.NOT_FOUND).entity(responseDTO).build(); } } + } diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java index 4b0d18b..868a5b8 100644 --- a/src/main/java/com/lions/dev/service/EventService.java +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -1,9 +1,12 @@ package com.lions.dev.service; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import jakarta.transaction.Transactional; +import com.lions.dev.dto.request.events.EventCreateRequestDTO; import com.lions.dev.entity.events.Events; import com.lions.dev.entity.users.Users; import com.lions.dev.repository.EventsRepository; -import com.lions.dev.dto.request.events.EventRequestDTO; import com.lions.dev.exception.EventNotFoundException; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -21,19 +24,27 @@ public class EventService { @Inject EventsRepository eventsRepository; + private static final Logger logger = LoggerFactory.getLogger(EventService.class); + /** * Crée un nouvel événement dans le système. * - * @param eventRequestDTO Le DTO contenant les informations de l'événement à créer. + * @param eventCreateRequestDTO Le DTO contenant les informations de l'événement à créer. * @param creator L'utilisateur créateur de l'événement. * @return L'événement créé. */ - public Events createEvent(EventRequestDTO eventRequestDTO, Users creator) { + public Events createEvent(EventCreateRequestDTO eventCreateRequestDTO, Users creator) { Events event = new Events(); - event.setTitle(eventRequestDTO.getTitle()); - event.setStartDate(eventRequestDTO.getStartDate()); - event.setEndDate(eventRequestDTO.getEndDate()); + event.setTitle(eventCreateRequestDTO.getTitle()); + event.setDescription(eventCreateRequestDTO.getDescription()); + event.setStartDate(eventCreateRequestDTO.getStartDate()); + event.setEndDate(eventCreateRequestDTO.getEndDate()); + event.setLocation(eventCreateRequestDTO.getLocation()); + event.setCategory(eventCreateRequestDTO.getCategory()); + event.setLink(eventCreateRequestDTO.getLink()); + event.setImageUrl(eventCreateRequestDTO.getImageUrl()); event.setCreator(creator); + event.setStatus("en cours"); eventsRepository.persist(event); System.out.println("[LOG] Événement créé : " + event.getTitle()); return event; @@ -50,7 +61,7 @@ public class EventService { Events event = eventsRepository.findById(id); if (event == null) { System.out.println("[ERROR] Événement non trouvé avec l'ID : " + id); - throw new EventNotFoundException("Événement non trouvé avec l'ID : " + id); + throw new EventNotFoundException(id); } System.out.println("[LOG] Événement trouvé avec l'ID : " + id); return event; @@ -74,12 +85,16 @@ public class EventService { * @param id L'ID de l'événement à supprimer. * @return true si l'événement a été supprimé, false sinon. */ + @Transactional public boolean deleteEvent(UUID id) { + logger.info("[LOG] Tentative de suppression de l'événement avec l'ID : {}", id); + boolean deleted = eventsRepository.deleteById(id); if (deleted) { - System.out.println("[LOG] Événement supprimé avec succès : " + id); + logger.info("[LOG] Événement avec l'ID {} supprimé avec succès.", id); } else { - System.out.println("[ERROR] Échec de la suppression de l'événement avec l'ID : " + id); + logger.warn("[LOG] Échec de la suppression : événement avec l'ID {} introuvable.", id); + throw new EventNotFoundException(id); } return deleted; } diff --git a/src/main/java/com/lions/dev/service/UserService.java b/src/main/java/com/lions/dev/service/UserService.java index 9a0d46a..9e5df8f 100644 --- a/src/main/java/com/lions/dev/service/UserService.java +++ b/src/main/java/com/lions/dev/service/UserService.java @@ -2,7 +2,6 @@ package com.lions.dev.service; import com.lions.dev.entity.users.Users; import com.lions.dev.repository.UsersRepository; -import com.lions.dev.dto.request.users.UserRequestDTO; import com.lions.dev.exception.UserNotFoundException; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -22,21 +21,21 @@ public class UserService { /** * Crée un nouvel utilisateur dans le système. * - * @param userRequestDTO Le DTO contenant les informations de l'utilisateur à créer. + * @param userCreateRequestDTO Le DTO contenant les informations de l'utilisateur à créer. * @return L'utilisateur créé. */ - public Users createUser(UserRequestDTO userRequestDTO) { + public Users createUser(com.lions.dev.dto.request.users.UserCreateRequestDTO userCreateRequestDTO) { Users user = new Users(); - user.setNom(userRequestDTO.getNom()); - user.setPrenoms(userRequestDTO.getPrenoms()); - user.setEmail(userRequestDTO.getEmail()); - user.setMotDePasse(userRequestDTO.getMotDePasse()); // Hachage automatique + user.setNom(userCreateRequestDTO.getNom()); + user.setPrenoms(userCreateRequestDTO.getPrenoms()); + user.setEmail(userCreateRequestDTO.getEmail()); + user.setMotDePasse(userCreateRequestDTO.getMotDePasse()); // Hachage automatique // Vérifier si le rôle est défini, sinon attribuer un rôle par défaut - if (userRequestDTO.getRole() == null || userRequestDTO.getRole().isEmpty()) { + if (userCreateRequestDTO.getRole() == null || userCreateRequestDTO.getRole().isEmpty()) { user.setRole("USER"); // Assigner un rôle par défaut, par exemple "USER" } else { - user.setRole(userRequestDTO.getRole()); + user.setRole(userCreateRequestDTO.getRole()); } usersRepository.persist(user); From d848f4596c884dbf0e1eab58a069eb0ed82617d2 Mon Sep 17 00:00:00 2001 From: DahoudG Date: Wed, 18 Sep 2024 10:33:56 +0000 Subject: [PATCH 2/8] Refactoring --- pom.xml | 327 +++++++++--------- .../com/lions/dev/entity/events/Events.java | 3 + .../com/lions/dev/entity/users/Users.java | 3 + .../lions/dev/resource/EventsResource.java | 140 ++++++-- .../dev/resource/FileUploadResource.java | 36 ++ .../com/lions/dev/resource/UsersResource.java | 48 ++- .../com/lions/dev/service/EventService.java | 30 ++ .../com/lions/dev/service/FileService.java | 35 ++ .../com/lions/dev/service/UserService.java | 33 ++ src/main/resources/application.properties | 5 + 10 files changed, 460 insertions(+), 200 deletions(-) create mode 100644 src/main/java/com/lions/dev/resource/FileUploadResource.java create mode 100644 src/main/java/com/lions/dev/service/FileService.java diff --git a/pom.xml b/pom.xml index c2dedb7..eee651b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,173 +1,174 @@ - - 4.0.0 - com.lions.dev - mic-after-work-server - 1.0.0-SNAPSHOT + + 4.0.0 + com.lions.dev + mic-after-work-server + 1.0.0-SNAPSHOT - - 3.13.0 - 17 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.13.0 - true - 3.2.5 - - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - + + 3.13.0 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.13.0 + true + 3.2.5 + + - - io.quarkus - quarkus-smallrye-jwt - - - - org.springframework.security - spring-security-core - 6.3.3 - - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - io.quarkiverse.groovy - quarkus-groovy-junit5 - 3.12.1 - - - io.quarkus - quarkus-smallrye-openapi - - - io.quarkus - quarkus-resteasy-reactive-jackson - - - io.quarkus - quarkus-hibernate-orm-panache - - - io.quarkus - quarkus-jdbc-oracle - - - io.quarkus - quarkus-arc - - - io.quarkus - quarkus-hibernate-orm - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - org.hibernate.validator - hibernate-validator - - org.projectlombok - lombok - 1.18.30 - provided + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - native-image-agent - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - - -parameters - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - ${maven.home} - - - - - + + + io.quarkus + quarkus-smallrye-jwt + + + org.springframework.security + spring-security-core + 6.3.3 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + io.quarkiverse.groovy + quarkus-groovy-junit5 + 3.12.1 + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-rest-jackson + + + io.quarkus + quarkus-hibernate-orm-panache + + + io.quarkus + quarkus-jdbc-oracle + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-hibernate-orm + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + org.hibernate.validator + hibernate-validator + + + org.projectlombok + lombok + 1.18.30 + provided + + - - - native - - - native - - - - false - true - - - + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + native-image-agent + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + + + ${project.build.directory}/${project.build.finalName}-runner + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + native + + + native + + + + false + true + + + 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 c50e437..bd58a98 100644 --- a/src/main/java/com/lions/dev/entity/events/Events.java +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -53,6 +53,9 @@ public class Events extends BaseEntity { @Column(name = "status", nullable = false) private String status = "en cours"; // 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/entity/users/Users.java b/src/main/java/com/lions/dev/entity/users/Users.java index 06435b7..545b1f2 100644 --- a/src/main/java/com/lions/dev/entity/users/Users.java +++ b/src/main/java/com/lions/dev/entity/users/Users.java @@ -38,6 +38,9 @@ public class Users extends BaseEntity { @Column(name = "role", nullable = false) private String role; // Le rôle de l'utilisateur (ADMIN, MODERATOR, USER, etc.) + @Column(name = "profile_image_url") + private String profileImageUrl; // L'URL de l'image de profil de l'utilisateur + // Utilisation de BCrypt pour hacher les mots de passe de manière sécurisée private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index ff4e893..9a045e6 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -1,17 +1,19 @@ package com.lions.dev.resource; -import com.lions.dev.dto.response.events.EventUpdateResponseDTO; -import com.lions.dev.dto.request.events.EventUpdateRequestDTO; -import com.lions.dev.entity.users.Users; -import com.lions.dev.dto.request.events.EventCreateRequestDTO; -import com.lions.dev.dto.response.events.EventCreateResponseDTO; -import com.lions.dev.entity.events.Events; +import com.lions.dev.service.EventService; import com.lions.dev.repository.EventsRepository; -import com.lions.dev.repository.UsersRepository; // Ajout du UsersRepository pour gérer les participants +import com.lions.dev.dto.request.events.EventCreateRequestDTO; +import com.lions.dev.dto.request.events.EventUpdateRequestDTO; +import com.lions.dev.dto.response.events.EventCreateResponseDTO; +import com.lions.dev.dto.response.events.EventUpdateResponseDTO; +import com.lions.dev.entity.events.Events; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.UsersRepository; // Ajout du UsersRepository pour gérer les import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; +import java.io.File; // participants import java.time.LocalDateTime; import java.util.List; import java.util.UUID; @@ -20,10 +22,10 @@ import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; /** - * Ressource REST pour la gestion des événements dans le système AfterWork. - * Cette classe expose des endpoints pour créer, récupérer, et supprimer des événements. + * Ressource REST pour la gestion des événements dans le système AfterWork. Cette classe expose des + * endpoints pour créer, récupérer, et supprimer des événements. * - * Tous les logs nécessaires pour la traçabilité sont intégrés. + *

Tous les logs nécessaires pour la traçabilité sont intégrés. */ @Path("/events") @Produces("application/json") @@ -35,7 +37,10 @@ public class EventsResource { EventsRepository eventsRepository; @Inject - UsersRepository usersRepository; // Ajout pour la gestion des participants + UsersRepository usersRepository; // Ajout pour la gestion des participants + + @Inject + EventService eventService; private static final Logger LOG = Logger.getLogger(EventsResource.class); @@ -47,9 +52,12 @@ public class EventsResource { */ @POST @Transactional - @Operation(summary = "Créer un nouvel événement", description = "Crée un nouvel événement et retourne ses détails") + @Operation( + summary = "Créer un nouvel événement", + description = "Crée un nouvel événement et retourne ses détails") public Response createEvent(EventCreateRequestDTO eventCreateRequestDTO) { - LOG.info("[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); + LOG.info( + "[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); Events event = new Events(); event.setTitle(eventCreateRequestDTO.getTitle()); @@ -77,7 +85,9 @@ public class EventsResource { */ @GET @Path("/{id}") - @Operation(summary = "Récupérer un événement par ID", description = "Retourne les détails de l'événement demandé") + @Operation( + summary = "Récupérer un événement par ID", + description = "Retourne les détails de l'événement demandé") public Response getEventById(@PathParam("id") UUID id) { LOG.info("[LOG] Récupération de l'événement avec l'ID : " + id); @@ -100,17 +110,22 @@ public class EventsResource { */ @GET @Path("/after-date") - @Operation(summary = "Récupérer les événements après une date", description = "Retourne les événements après une date donnée") + @Operation( + summary = "Récupérer les événements après une date", + description = "Retourne les événements après une date donnée") public Response getEventsAfterDate(@QueryParam("startDate") LocalDateTime startDate) { LOG.info("[LOG] Récupération des événements après la date : " + startDate); List events = eventsRepository.findEventsAfterDate(startDate); if (events.isEmpty()) { LOG.warn("[LOG] Aucun événement trouvé après la date : " + startDate); - return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé après cette date.").build(); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé après cette date.") + .build(); } - List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + List responseDTOs = + events.stream().map(EventCreateResponseDTO::new).toList(); LOG.info("[LOG] Nombre d'événements trouvés après la date : " + events.size()); return Response.ok(responseDTOs).build(); } @@ -124,7 +139,9 @@ public class EventsResource { @DELETE @Path("/{id}") @Transactional - @Operation(summary = "Supprimer un événement", description = "Supprime un événement de la base de données") + @Operation( + summary = "Supprimer un événement", + description = "Supprime un événement de la base de données") public Response deleteEvent(@PathParam("id") UUID id) { LOG.info("Tentative de suppression de l'événement avec l'ID : " + id); @@ -134,8 +151,7 @@ public class EventsResource { return Response.noContent().build(); } else { LOG.warn("Échec de la suppression : événement introuvable avec l'ID : " + id); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement non trouvé.").build(); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } } @@ -149,15 +165,16 @@ public class EventsResource { @POST @Path("/{id}/participants") @Transactional - @Operation(summary = "Ajouter un participant à un événement", description = "Ajoute un utilisateur à un événement") + @Operation( + summary = "Ajouter un participant à un événement", + description = "Ajoute un utilisateur à un événement") public Response addParticipant(@PathParam("id") UUID eventId, Users user) { LOG.info("Ajout d'un participant à l'événement : " + eventId); 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(); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } event.addParticipant(user); @@ -176,22 +193,23 @@ public class EventsResource { @DELETE @Path("/{id}/participants/{userId}") @Transactional - @Operation(summary = "Retirer un participant d'un événement", description = "Supprime un utilisateur de la liste des participants d'un événement") - public Response removeParticipant(@PathParam("id") UUID eventId, @PathParam("userId") UUID userId) { + @Operation( + summary = "Retirer un participant d'un événement", + description = "Supprime un utilisateur de la liste des participants d'un événement") + public Response removeParticipant( + @PathParam("id") UUID eventId, @PathParam("userId") UUID userId) { LOG.info("Retrait d'un participant de l'événement : " + eventId); 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(); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } Users user = usersRepository.findById(userId); if (user == null) { LOG.warn("Utilisateur non trouvé avec l'ID : " + userId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Utilisateur non trouvé.").build(); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); } event.removeParticipant(user); @@ -208,15 +226,16 @@ public class EventsResource { */ @GET @Path("/{id}/participants/count") - @Operation(summary = "Obtenir le nombre de participants à un événement", description = "Retourne le nombre total de participants à un événement") + @Operation( + summary = "Obtenir le nombre de participants à un événement", + description = "Retourne le nombre total de participants à un événement") public Response getNumberOfParticipants(@PathParam("id") UUID eventId) { LOG.info("Récupération du nombre de participants pour l'événement : " + eventId); 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(); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } int participantCount = event.getNumberOfParticipants(); @@ -233,15 +252,16 @@ public class EventsResource { @POST @Path("/{id}/close") @Transactional - @Operation(summary = "Fermer un événement", description = "Ferme un événement et empêche les nouvelles participations") + @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); 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(); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } event.setClosed(true); // Marquer l'événement comme fermé @@ -261,7 +281,8 @@ public class EventsResource { @Path("/{id}") @Transactional @Operation(summary = "Mettre à jour un événement", description = "Modifie un événement existant") - public Response updateEvent(@PathParam("id") UUID id, EventUpdateRequestDTO eventUpdateRequestDTO) { + public Response updateEvent( + @PathParam("id") UUID id, EventUpdateRequestDTO eventUpdateRequestDTO) { LOG.info("[LOG] Tentative de mise à jour de l'événement avec l'ID : " + id); Events event = eventsRepository.findById(id); @@ -287,4 +308,51 @@ public class EventsResource { return Response.ok(responseDTO).build(); } + /** + * Endpoint pour mettre à jour l'image d'un événement. + * + * @param id L'identifiant de l'événement. + * @param imageFilePath Le chemin vers l'image de l'événement. + * @return Un message indiquant si la mise à jour a réussi ou non. + */ + @PUT + @jakarta.ws.rs.Path("/{id}/image") + public String updateEventImage(@PathParam("id") UUID id, String imageFilePath) { + try { + // Vérification si le chemin d'image est vide ou null + if (imageFilePath == null || imageFilePath.isEmpty()) { + System.out.println("[ERROR] Le chemin de l'image est vide ou null."); + return "Le chemin de l'image est vide ou null."; + } + + // Utiliser File pour vérifier si le fichier existe + File file = new File(imageFilePath); + if (!file.exists()) { + System.out.println("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); + return "Le fichier spécifié n'existe pas."; + } + + // Récupérer l'événement par son ID + Events event = eventService.getEventById(id); + if (event == null) { + System.out.println("[ERROR] Événement non trouvé avec l'ID : " + id); + return "Événement non trouvé."; + } + + // Mettre à jour l'URL de l'image de l'événement + String imageUrl = file.getAbsolutePath(); // Obtenir le chemin complet du fichier + event.setImageUrl(imageUrl); + + // Mise à jour de l'événement + eventService.updateEvent(event); + System.out.println( + "[LOG] Image de l'événement mise à jour avec succès pour : " + event.getTitle()); + + return "Image de l'événement mise à jour avec succès."; + } catch (Exception e) { + System.out.println( + "[ERROR] Erreur lors de la mise à jour de l'image de l'événement : " + e.getMessage()); + return "Erreur lors de la mise à jour de l'image de l'événement."; + } + } } diff --git a/src/main/java/com/lions/dev/resource/FileUploadResource.java b/src/main/java/com/lions/dev/resource/FileUploadResource.java new file mode 100644 index 0000000..3451b8c --- /dev/null +++ b/src/main/java/com/lions/dev/resource/FileUploadResource.java @@ -0,0 +1,36 @@ +package com.lions.dev.resource; + +import com.lions.dev.service.FileService; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.RestForm; +import org.jboss.resteasy.reactive.multipart.FileUpload; +import jakarta.inject.Inject; +import java.io.IOException; + +@Path("/upload") +public class FileUploadResource { + + private static final Logger LOG = Logger.getLogger(FileUploadResource.class); + + @Inject + FileService fileService; + + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response uploadFile(@RestForm("file") FileUpload file) { + String uploadDir = "/tmp/uploads/"; + + try { + Path savedFilePath = (jakarta.ws.rs.Path) fileService.saveFile(file.uploadedFile(), uploadDir, file.fileName()); + return Response.ok("Fichier uploadé avec succès : " + savedFilePath).build(); + } catch (IOException e) { + LOG.error("Erreur lors de l'upload du fichier", e); + return Response.serverError().entity("Erreur lors de l'upload du fichier.").build(); + } + } +} diff --git a/src/main/java/com/lions/dev/resource/UsersResource.java b/src/main/java/com/lions/dev/resource/UsersResource.java index 836788c..3680539 100644 --- a/src/main/java/com/lions/dev/resource/UsersResource.java +++ b/src/main/java/com/lions/dev/resource/UsersResource.java @@ -1,5 +1,8 @@ package com.lions.dev.resource; +import java.io.File; + +import jakarta.ws.rs.Path; import com.lions.dev.dto.request.users.UserAuthenticateRequestDTO; import com.lions.dev.dto.response.users.UserAuthenticateResponseDTO; import com.lions.dev.dto.response.users.UserDeleteResponseDto; @@ -14,6 +17,7 @@ import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; + /** * Ressource REST pour la gestion des utilisateurs dans le système AfterWork. Cette classe expose * des endpoints pour créer, authentifier, récupérer et supprimer des utilisateurs. @@ -26,7 +30,8 @@ import org.jboss.logging.Logger; @Tag(name = "Users", description = "Opérations liées à la gestion des utilisateurs") public class UsersResource { - @Inject UserService userService; + @Inject + UserService userService; private static final Logger LOG = Logger.getLogger(UsersResource.class); @@ -145,4 +150,45 @@ public class UsersResource { } } + /** + * Endpoint pour mettre à jour l'image de profil de l'utilisateur. + * + * @param id L'identifiant de l'utilisateur. + * @param imageFilePath Le chemin vers l'image de profil. + * @return Un message indiquant si la mise à jour a réussi. + */ + @PUT + @jakarta.ws.rs.Path("/{id}/profile-image") // Annotation REST avec jakarta.ws.rs.Path + public String updateUserProfileImage(@PathParam("id") UUID id, String imageFilePath) { + try { + // Utiliser File au lieu de Path pour vérifier si le fichier existe + File file = new File(imageFilePath); + if (!file.exists()) { + System.out.println("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); + return "Le fichier spécifié n'existe pas."; + } + + // Récupérer l'utilisateur par son ID + Users user = userService.getUserById(id); + if (user == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + return "Utilisateur non trouvé."; + } + + // Mettre à jour l'URL de l'image de profil + String profileImageUrl = file.getAbsolutePath(); // Obtenir le chemin complet du fichier + user.setProfileImageUrl(profileImageUrl); + + // Mise à jour de l'utilisateur + userService.updateUser(user); + System.out.println("[LOG] Image de profil mise à jour pour l'utilisateur : " + user.getEmail()); + + return "Image de profil mise à jour avec succès."; + } catch (Exception e) { + System.out.println("[ERROR] Erreur lors de la mise à jour de l'image de profil : " + e.getMessage()); + return "Erreur lors de la mise à jour de l'image de profil."; + } + } + + } diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java index 868a5b8..6e155b3 100644 --- a/src/main/java/com/lions/dev/service/EventService.java +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -98,4 +98,34 @@ public class EventService { } return deleted; } + + /** + * Met à jour un événement dans le système. + * + * @param event L'événement à mettre à jour. + * @return L'événement mis à jour. + */ + @Transactional + public Events updateEvent(Events event) { + Events existingEvent = eventsRepository.findById(event.getId()); + if (existingEvent == null) { + logger.error("[ERROR] Événement non trouvé avec l'ID : {}", event.getId()); + throw new EventNotFoundException(event.getId()); + } + + // Mettre à jour les détails de l'événement + existingEvent.setTitle(event.getTitle()); + existingEvent.setDescription(event.getDescription()); + existingEvent.setStartDate(event.getStartDate()); + existingEvent.setEndDate(event.getEndDate()); + existingEvent.setLocation(event.getLocation()); + existingEvent.setCategory(event.getCategory()); + existingEvent.setLink(event.getLink()); + existingEvent.setImageUrl(event.getImageUrl()); + existingEvent.setStatus(event.getStatus()); + + eventsRepository.persist(existingEvent); + logger.info("[LOG] Événement mis à jour avec succès : {}", existingEvent.getTitle()); + return existingEvent; + } } diff --git a/src/main/java/com/lions/dev/service/FileService.java b/src/main/java/com/lions/dev/service/FileService.java new file mode 100644 index 0000000..ff5f5a3 --- /dev/null +++ b/src/main/java/com/lions/dev/service/FileService.java @@ -0,0 +1,35 @@ +package com.lions.dev.service; + +import org.jboss.logging.Logger; +import jakarta.enterprise.context.ApplicationScoped; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Service pour la gestion des fichiers uploadés. + * Ce service permet de sauvegarder et gérer les fichiers uploadés sur le serveur. + */ +@ApplicationScoped +public class FileService { + + private static final Logger LOG = Logger.getLogger(FileService.class); + + /** + * Sauvegarde le fichier uploadé sur le serveur. + * + * @param uploadedFilePath Le chemin temporaire du fichier uploadé. + * @param destinationDir Le répertoire de destination où sauvegarder le fichier. + * @param fileName Le nom du fichier. + * @return Le chemin complet du fichier sauvegardé. + * @throws IOException Si une erreur survient lors de la sauvegarde. + */ + public Path saveFile(Path uploadedFilePath, String destinationDir, String fileName) throws IOException { + Path destination = Paths.get(destinationDir, fileName); + Files.createDirectories(Paths.get(destinationDir)); // Crée le répertoire s'il n'existe pas + Files.copy(uploadedFilePath, destination); // Copie le fichier vers sa destination + LOG.info("Fichier sauvegardé avec succès : " + destination); + return destination; + } +} diff --git a/src/main/java/com/lions/dev/service/UserService.java b/src/main/java/com/lions/dev/service/UserService.java index 9e5df8f..15f920d 100644 --- a/src/main/java/com/lions/dev/service/UserService.java +++ b/src/main/java/com/lions/dev/service/UserService.java @@ -43,6 +43,37 @@ public class UserService { return user; } + /** + * Met à jour un utilisateur existant dans le système. + * + * @param user L'utilisateur à mettre à jour. + * @return L'utilisateur mis à jour. + */ + public Users updateUser(Users user) { + try { + Users existingUser = usersRepository.findById(user.getId()); + if (existingUser == null) { + System.out.println("[ERROR] Utilisateur non trouvé pour la mise à jour avec l'ID : " + user.getId()); + throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + user.getId()); + } + + // Mettre à jour les champs de l'utilisateur existant + existingUser.setNom(user.getNom()); + existingUser.setPrenoms(user.getPrenoms()); + existingUser.setEmail(user.getEmail()); + existingUser.setMotDePasse(user.getMotDePasse()); // Hachage automatique si nécessaire + existingUser.setRole(user.getRole()); + + usersRepository.persist(existingUser); + System.out.println("[LOG] Utilisateur mis à jour avec succès : " + existingUser.getEmail()); + return existingUser; + } catch (Exception e) { + System.out.println("[ERROR] Erreur lors de la mise à jour de l'utilisateur : " + e.getMessage()); + throw e; + } + } + + /** * Authentifie un utilisateur avec son email et son mot de passe. * @@ -93,4 +124,6 @@ public class UserService { } return deleted; } + + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4fc0968..5cb4d5e 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -27,3 +27,8 @@ quarkus.log.level=INFO # smallrye.jwt.sign.key.location=META-INF/resources/privateKey.pem # smallrye.jwt.sign.key.algorithm=RS256 # smallrye.jwt.token.lifetime=3600 + +# Activer le support multipart +quarkus.http.body.uploads-directory=/tmp/uploads +quarkus.http.body.multipart.max-file-size=10M +quarkus.http.body.multipart.max-request-size=15M From f84b49f9d7c387a2c5b8557c732c4c310b64877a Mon Sep 17 00:00:00 2001 From: DahoudG Date: Tue, 24 Sep 2024 00:31:52 +0000 Subject: [PATCH 3/8] Checkpoint & Refactoring --- .../request/events/EventCreateRequestDTO.java | 12 +- ...TO.java => EventGetOneByIdRequestDTO.java} | 4 +- .../events/EventCreateResponseDTO.java | 2 + .../dev/repository/EventsRepository.java | 26 +- .../lions/dev/resource/EventsResource.java | 274 ++++++++++++++++-- .../com/lions/dev/service/EventService.java | 60 +++- 6 files changed, 343 insertions(+), 35 deletions(-) rename src/main/java/com/lions/dev/dto/request/events/{EventReadRequestDTO.java => EventGetOneByIdRequestDTO.java} (86%) diff --git a/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java index c411a59..422e445 100644 --- a/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/events/EventCreateRequestDTO.java @@ -1,6 +1,8 @@ package com.lions.dev.dto.request.events; -import com.lions.dev.entity.users.Users; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import java.time.LocalDateTime; @@ -10,8 +12,8 @@ import java.time.LocalDateTime; * Ce DTO est utilisé dans les requêtes de création d'événements, envoyant les informations * nécessaires comme le titre, les dates, la description, le créateur, et d'autres attributs. */ -@lombok.Getter -@lombok.Setter +@Getter +@Setter public class EventCreateRequestDTO { @NotNull(message = "Le titre de l'événement est obligatoire.") @@ -31,8 +33,8 @@ public class EventCreateRequestDTO { private String link; // Lien d'information supplémentaire private String imageUrl; // URL de l'image associée à l'événement - @NotNull(message = "Le créateur de l'événement est obligatoire.") - private Users creator; // Utilisateur créateur de l'événement + @NotNull(message = "L'identifiant du créateur est obligatoire.") + private UUID creatorId; // Identifiant du créateur de l'événement public EventCreateRequestDTO() { System.out.println("[LOG] DTO de requête de création d'événement initialisé."); diff --git a/src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java similarity index 86% rename from src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java rename to src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java index 46c5983..3a07606 100644 --- a/src/main/java/com/lions/dev/dto/request/events/EventReadRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java @@ -9,12 +9,12 @@ import java.util.UUID; */ @lombok.Getter @lombok.Setter -public class EventReadRequestDTO { +public class EventGetOneByIdRequestDTO { @NotNull(message = "L'ID de l'événement est obligatoire.") private UUID eventId; // ID de l'événement à lire - public EventReadRequestDTO() { + public EventGetOneByIdRequestDTO() { System.out.println("[LOG] DTO de requête de lecture d'événement initialisé."); } } 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 3a7ed79..7c79188 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 @@ -11,6 +11,7 @@ import java.time.LocalDateTime; @lombok.Getter public class EventCreateResponseDTO { + private String id; // Identifiant de l'événement private String title; // Titre de l'événement private String description; // Description de l'événement private LocalDateTime startDate; // Date de début de l'événement @@ -27,6 +28,7 @@ public class EventCreateResponseDTO { * @param event L'événement à convertir en DTO. */ public EventCreateResponseDTO(Events event) { + this.id = event.getId().toString(); this.title = event.getTitle(); this.description = event.getDescription(); this.startDate = event.getStartDate(); diff --git a/src/main/java/com/lions/dev/repository/EventsRepository.java b/src/main/java/com/lions/dev/repository/EventsRepository.java index 146f988..a9fce37 100644 --- a/src/main/java/com/lions/dev/repository/EventsRepository.java +++ b/src/main/java/com/lions/dev/repository/EventsRepository.java @@ -6,6 +6,7 @@ import jakarta.enterprise.context.ApplicationScoped; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; +import org.jboss.logging.Logger; /** * Repository pour l'entité Events. @@ -15,6 +16,8 @@ import java.util.UUID; @ApplicationScoped public class EventsRepository implements PanacheRepositoryBase { + private static final Logger LOG = Logger.getLogger(EventsRepository.class); + /** * Récupère tous les événements après une date donnée. * @@ -22,9 +25,28 @@ public class EventsRepository implements PanacheRepositoryBase { * @return Une liste d'événements après cette date. */ public List findEventsAfterDate(LocalDateTime startDate) { - System.out.println("[LOG] Récupération des événements après la date : " + startDate); + LOG.info("[LOG] Récupération des événements après la date : " + startDate); List events = list("startDate > ?1", startDate); - System.out.println("[LOG] Nombre d'événements trouvés après la date " + startDate + " : " + events.size()); + LOG.info("[LOG] Nombre d'événements trouvés après la date " + startDate + " : " + events.size()); + return events; + } + + /** + * Récupère tous les événements entre deux dates. + * + * @param startDate La date de début de filtre. + * @param endDate La date de fin de filtre. + * @return Une liste d'événements entre ces deux dates. + */ + public List findEventsBetweenDates(LocalDateTime startDate, LocalDateTime endDate) { + if (endDate.isBefore(startDate)) { + LOG.warn("[LOG] La date de fin " + endDate + " est antérieure à la date de début " + startDate); + return List.of(); // Retourner une liste vide en cas de dates invalides + } + + LOG.info("[LOG] Récupération des événements entre les dates : " + startDate + " et " + endDate); + List events = list("startDate >= ?1 and endDate <= ?2", startDate, endDate); + LOG.info("[LOG] Nombre d'événements trouvés entre les dates " + startDate + " et " + endDate + " : " + events.size()); return events; } } diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 9a045e6..5036f12 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -17,6 +17,7 @@ import java.io.File; // participants import java.time.LocalDateTime; import java.util.List; import java.util.UUID; +import com.lions.dev.core.errors.exceptions.EventNotFoundException; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; @@ -59,18 +60,15 @@ public class EventsResource { LOG.info( "[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); - Events event = new Events(); - event.setTitle(eventCreateRequestDTO.getTitle()); - event.setStartDate(eventCreateRequestDTO.getStartDate()); - event.setEndDate(eventCreateRequestDTO.getEndDate()); - event.setDescription(eventCreateRequestDTO.getDescription()); - event.setLocation(eventCreateRequestDTO.getLocation()); - event.setCategory(eventCreateRequestDTO.getCategory()); - event.setLink(eventCreateRequestDTO.getLink()); - event.setImageUrl(eventCreateRequestDTO.getImageUrl()); - event.setCreator(eventCreateRequestDTO.getCreator()); + // Récupérer l'utilisateur créateur à partir de l'identifiant + Users creator = usersRepository.findById(eventCreateRequestDTO.getCreatorId()); + if (creator == null) { + LOG.error("[ERROR] Créateur non trouvé avec l'ID : " + eventCreateRequestDTO.getCreatorId()); + return Response.status(Response.Status.BAD_REQUEST).entity("Créateur non trouvé").build(); + } - eventsRepository.persist(event); + // Appel au service pour créer l'événement + Events event = eventService.createEvent(eventCreateRequestDTO, creator); LOG.info("[LOG] Événement créé avec succès : " + event.getTitle()); EventCreateResponseDTO responseDTO = new EventCreateResponseDTO(event); @@ -116,17 +114,21 @@ public class EventsResource { public Response getEventsAfterDate(@QueryParam("startDate") LocalDateTime startDate) { LOG.info("[LOG] Récupération des événements après la date : " + startDate); - List events = eventsRepository.findEventsAfterDate(startDate); + // Appel au service pour récupérer les événements après une date donnée + List events = eventService.getEventsAfterDate(startDate); if (events.isEmpty()) { LOG.warn("[LOG] Aucun événement trouvé après la date : " + startDate); return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé après cette date.") - .build(); + .entity("Aucun événement trouvé après cette date.") + .build(); } - List responseDTOs = - events.stream().map(EventCreateResponseDTO::new).toList(); + // Transformer la liste des événements en DTO pour la réponse + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); LOG.info("[LOG] Nombre d'événements trouvés après la date : " + events.size()); + return Response.ok(responseDTOs).build(); } @@ -145,16 +147,23 @@ public class EventsResource { public Response deleteEvent(@PathParam("id") UUID id) { LOG.info("Tentative de suppression de l'événement avec l'ID : " + id); - boolean deleted = eventsRepository.deleteById(id); - if (deleted) { - LOG.info("Événement supprimé avec succès."); - return Response.noContent().build(); - } else { - LOG.warn("Échec de la suppression : événement introuvable avec l'ID : " + id); + // Appel du service pour la suppression de l'événement + try { + boolean deleted = eventService.deleteEvent(id); + if (deleted) { + LOG.info("Événement supprimé avec succès."); + return Response.noContent().build(); + } else { + LOG.warn("Échec de la suppression : événement introuvable avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + } catch (EventNotFoundException e) { + LOG.error("[ERROR] Échec de la suppression : " + e.getMessage()); return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } } + /** * Endpoint pour ajouter un participant à un événement. * @@ -355,4 +364,225 @@ public class EventsResource { return "Erreur lors de la mise à jour de l'image de l'événement."; } } + + /** + * Endpoint pour récupérer la liste de tous les événements. + * + * @return Une réponse HTTP contenant la liste des événements. + */ + @GET + @Operation( + summary = "Récupérer tous les événements", + description = "Retourne la liste de tous les événements disponibles") + public Response getAllEvents() { + LOG.info("[LOG] Récupération de tous les événements disponibles"); + + List events = eventsRepository.findAll().list(); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé."); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé.") + .build(); + } + + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre total d'événements trouvés : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + /** + * Endpoint pour récupérer les événements par catégorie. + * + * @param category La catégorie d'événement à filtrer. + * @return Une réponse HTTP contenant la liste des événements dans cette catégorie. + */ + @GET + @Path("/category/{category}") + @Operation( + summary = "Récupérer les événements par catégorie", + description = "Retourne la liste des événements correspondant à une catégorie donnée") + public Response getEventsByCategory(@PathParam("category") String category) { + LOG.info("[LOG] Récupération des événements dans la catégorie : " + category); + + List events = eventService.findEventsByCategory(category); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé pour la catégorie : " + category); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé pour cette catégorie.") + .build(); + } + + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés dans la catégorie '" + category + "' : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + /** + * Endpoint pour mettre à jour le statut d'un événement. + * + * @param id L'ID de l'événement. + * @param status Le nouveau statut de l'événement. + * @return Une réponse HTTP indiquant la mise à jour du statut. + */ + @PUT + @Path("/{id}/status") + @Transactional + @Operation( + summary = "Mettre à jour le statut d'un événement", + description = "Modifie le statut d'un événement (ouvert, fermé, annulé, etc.)") + public Response updateEventStatus(@PathParam("id") UUID id, @QueryParam("status") String status) { + LOG.info("[LOG] Mise à jour du statut de l'événement avec l'ID : " + id); + + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + event.setStatus(status); + eventsRepository.persist(event); + LOG.info("[LOG] Statut de l'événement mis à jour avec succès : " + status); + + EventUpdateResponseDTO responseDTO = new EventUpdateResponseDTO(event); + return Response.ok(responseDTO).build(); + } + + /** + * Endpoint pour rechercher des événements par mots-clés. + * + * @param keyword Le mot-clé à rechercher. + * @return Une réponse HTTP contenant la liste des événements correspondant au mot-clé. + */ + @GET + @Path("/search") + @Operation( + summary = "Rechercher des événements par mots-clés", + description = "Retourne la liste des événements dont le titre ou la description contient les mots-clés spécifiés") + public Response searchEvents(@QueryParam("keyword") String keyword) { + LOG.info("[LOG] Recherche d'événements avec le mot-clé : " + keyword); + + List events = eventService.searchEvents(keyword); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé avec le mot-clé : " + keyword); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé pour ce mot-clé.") + .build(); + } + + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés avec le mot-clé '" + keyword + "' : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + /** + * Endpoint pour récupérer les événements auxquels un utilisateur est inscrit. + * + * @param userId L'ID de l'utilisateur. + * @return Une réponse HTTP contenant la liste des événements. + */ + @GET + @Path("/user/{userId}") + @Operation( + summary = "Récupérer les événements auxquels un utilisateur est inscrit", + description = "Retourne la liste des événements auxquels un utilisateur spécifique est inscrit") + public Response getEventsByUser(@PathParam("userId") UUID userId) { + LOG.info("[LOG] Récupération des événements pour l'utilisateur avec l'ID : " + userId); + + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + } + + List events = eventService.findEventsByUser(user); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé pour l'utilisateur avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé.").build(); + } + + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés pour l'utilisateur : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + /** + * Endpoint pour récupérer les événements par statut. + * + * @param status Le statut des événements à filtrer (en cours, terminé, etc.). + * @return Une réponse HTTP contenant la liste des événements avec ce statut. + */ + @GET + @Path("/status/{status}") + @Operation( + summary = "Récupérer les événements par statut", + description = "Retourne la liste des événements correspondant à un statut spécifique") + public Response getEventsByStatus(@PathParam("status") String status) { + LOG.info("[LOG] Récupération des événements avec le statut : " + status); + + List events = eventService.findEventsByStatus(status); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé avec le statut : " + status); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé pour ce statut.") + .build(); + } + + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés avec le statut '" + status + "' : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + /** + * Endpoint pour récupérer les événements entre deux dates spécifiques. + * + * @param startDate La date de début pour filtrer les événements. + * @param endDate La date de fin pour filtrer les événements. + * @return Une réponse HTTP contenant la liste des événements entre les deux dates. + */ + @GET + @Path("/between-dates") + @Operation( + summary = "Récupérer les événements entre deux dates", + description = "Retourne la liste des événements qui se déroulent entre deux dates spécifiques") + public Response findEventsBetweenDates( + @QueryParam("startDate") LocalDateTime startDate, + @QueryParam("endDate") LocalDateTime endDate) { + + LOG.info("[LOG] Récupération des événements entre les dates : " + startDate + " et " + endDate); + + // Vérification de la validité des dates + if (startDate == null || endDate == null || endDate.isBefore(startDate)) { + LOG.error("[ERROR] Les dates fournies sont invalides."); + return Response.status(Response.Status.BAD_REQUEST) + .entity("Les dates sont invalides ou mal formatées.") + .build(); + } + + // Appel au service pour récupérer les événements entre les dates données + List events = eventService.findEventsBetweenDates(startDate, endDate); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé entre les dates : " + startDate + " et " + endDate); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé entre ces dates.") + .build(); + } + + // Transformation des événements en DTO pour la réponse + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés entre les dates : " + events.size()); + return Response.ok(responseDTOs).build(); + } + } diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java index 6e155b3..31fa4e0 100644 --- a/src/main/java/com/lions/dev/service/EventService.java +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -45,8 +45,9 @@ public class EventService { event.setImageUrl(eventCreateRequestDTO.getImageUrl()); event.setCreator(creator); event.setStatus("en cours"); + eventsRepository.persist(event); - System.out.println("[LOG] Événement créé : " + event.getTitle()); + logger.info("[LOG] Événement créé avec succès : {}", event.getTitle()); return event; } @@ -60,10 +61,10 @@ public class EventService { public Events getEventById(UUID id) { Events event = eventsRepository.findById(id); if (event == null) { - System.out.println("[ERROR] Événement non trouvé avec l'ID : " + id); + logger.error("[ERROR] Événement non trouvé avec l'ID : {}", id); throw new EventNotFoundException(id); } - System.out.println("[LOG] Événement trouvé avec l'ID : " + id); + logger.info("[LOG] Événement trouvé avec l'ID : {}", id); return event; } @@ -75,7 +76,7 @@ public class EventService { */ public List getEventsAfterDate(LocalDateTime startDate) { List events = eventsRepository.findEventsAfterDate(startDate); - System.out.println("[LOG] Nombre d'événements trouvés après la date " + startDate + " : " + events.size()); + logger.info("[LOG] Nombre d'événements trouvés après la date {} : {}", startDate, events.size()); return events; } @@ -128,4 +129,55 @@ public class EventService { logger.info("[LOG] Événement mis à jour avec succès : {}", existingEvent.getTitle()); return existingEvent; } + + /** + * Récupère les événements par catégorie. + * + * @param category La catégorie des événements. + * @return La liste des événements dans cette catégorie. + */ + public List findEventsByCategory(String category) { + return eventsRepository.find("category", category).list(); + } + + /** + * Recherche des événements par mot-clé. + * + * @param keyword Le mot-clé à rechercher. + * @return La liste des événements correspondant au mot-clé. + */ + public List searchEvents(String keyword) { + return eventsRepository.find("title like ?1 or description like ?1", "%" + keyword + "%").list(); + } + + /** + * Récupère les événements d'un utilisateur. + * + * @param user L'utilisateur pour lequel récupérer les événements. + * @return La liste des événements auxquels l'utilisateur participe. + */ + public List findEventsByUser(Users user) { + return eventsRepository.find("participants", user).list(); + } + + /** + * Récupère les événements par statut. + * + * @param status Le statut des événements (en cours, fermé, etc.). + * @return La liste des événements ayant ce statut. + */ + public List findEventsByStatus(String status) { + return eventsRepository.find("status", status).list(); + } + + /** + * Récupère les événements entre deux dates. + * + * @param startDate La date de début. + * @param endDate La date de fin. + * @return La liste des événements entre ces deux dates. + */ + public List findEventsBetweenDates(LocalDateTime startDate, LocalDateTime endDate) { + return eventsRepository.findEventsBetweenDates(startDate, endDate); + } } From 800fdd4d12c5df015b02be6881a0577d3da68456 Mon Sep 17 00:00:00 2001 From: DahoudG Date: Wed, 25 Sep 2024 21:28:56 +0000 Subject: [PATCH 4/8] =?UTF-8?q?Mise=20=C3=A0=20jour=20statut=20=C3=A9v?= =?UTF-8?q?=C3=A9nement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/events/EventUpdateRequestDTO.java | 1 + .../events/EventCreateResponseDTO.java | 2 ++ .../com/lions/dev/entity/events/Events.java | 5 +-- .../lions/dev/resource/EventsResource.java | 33 +++++++++++++++++++ .../com/lions/dev/service/EventService.java | 2 +- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java index 137a4c1..e0f1605 100644 --- a/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/events/EventUpdateRequestDTO.java @@ -19,4 +19,5 @@ public class EventUpdateRequestDTO { private String category; private String link; private String imageUrl; + private String status; } 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 7c79188..96d3d08 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,6 +21,7 @@ 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; /** * Constructeur qui transforme une entité Events en DTO. @@ -38,5 +39,6 @@ public class EventCreateResponseDTO { this.link = event.getLink(); this.imageUrl = event.getImageUrl(); this.creatorEmail = event.getCreator().getEmail(); + this.status = event.getStatus(); } } 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 bd58a98..2c95050 100644 --- a/src/main/java/com/lions/dev/entity/events/Events.java +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -51,7 +51,7 @@ public class Events extends BaseEntity { private String imageUrl; // URL d'une image associée à l'événement @Column(name = "status", nullable = false) - private String status = "en cours"; // Le statut de l'événement (en cours, terminé, annulé, etc.) + 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 @@ -105,7 +105,8 @@ public class Events extends BaseEntity { * Ferme l'événement en changeant son statut. */ public void setClosed(boolean closed) { - this.status = closed ? "fermé" : "en cours"; + this.status = closed ? "fermé" : "ouvert"; System.out.println("[LOG] Statut de l'événement mis à jour : " + this.title + " - " + this.status); } + } diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 5036f12..24b9883 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -279,6 +279,39 @@ public class EventsResource { return Response.ok(new EventCreateResponseDTO(event)).build(); } + /** + * Endpoint pour réouvrir un événement. + * + * @param eventId L'ID de l'événement. + * @return Une réponse HTTP indiquant le succès de la réouverture. + */ + @POST + @Path("/{id}/reopen") + @Transactional + @Operation( + summary = "Réouvrir un événement", + description = "Réouvre un événement et permet à nouveau les participations") + public Response reopenEvent(@PathParam("id") UUID eventId) { + LOG.info("Tentative de réouverture de l'événement avec l'ID : " + eventId); + 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(); + } + + if ("ouvert".equals(event.getStatus())) { + LOG.warn("L'événement avec l'ID " + eventId + " est déjà ouvert."); + return Response.status(Response.Status.BAD_REQUEST).entity("L'événement est déjà ouvert.").build(); + } + + event.setStatus("ouvert"); // Marquer l'événement comme ouvert + eventsRepository.persist(event); + LOG.info("Événement réouvert avec succès : " + event.getTitle()); + return Response.ok(new EventCreateResponseDTO(event)).build(); + } + + /** * Endpoint pour mettre à jour un événement. * diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java index 31fa4e0..c2ff8c2 100644 --- a/src/main/java/com/lions/dev/service/EventService.java +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -44,7 +44,7 @@ public class EventService { event.setLink(eventCreateRequestDTO.getLink()); event.setImageUrl(eventCreateRequestDTO.getImageUrl()); event.setCreator(creator); - event.setStatus("en cours"); + event.setStatus("ouvert"); eventsRepository.persist(event); logger.info("[LOG] Événement créé avec succès : {}", event.getTitle()); From 2c7d6715881fbbb6cb332dcd7d5cb14d338b190f Mon Sep 17 00:00:00 2001 From: DahoudG Date: Thu, 10 Oct 2024 00:39:01 +0000 Subject: [PATCH 5/8] =?UTF-8?q?Refactoring=20et=20am=C3=A9lioration=20des?= =?UTF-8?q?=20endpoints=20friendship?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/errors/GlobalExceptionHandler.java | 46 ++- .../exceptions/BadRequestException.java | 1 + .../request/friends/FriendshipRequestDTO.java | 25 ++ .../request/users/UserCreateRequestDTO.java | 2 + .../FriendshipRequestStatusResponseDTO.java | 57 ++++ .../friends/FriendshipResponseDTO.java | 36 ++ .../response/users/UserCreateResponseDTO.java | 5 +- .../lions/dev/entity/friends/Friendship.java | 54 +++ .../dev/entity/friends/FriendshipStatus.java | 7 + .../FriendshipNotFoundException.java | 15 + .../dev/repository/FriendshipRepository.java | 80 +++++ .../dev/resource/FriendshipResource.java | 317 ++++++++++++++++++ .../com/lions/dev/resource/UsersResource.java | 148 ++++---- .../lions/dev/service/FriendshipService.java | 184 ++++++++++ .../com/lions/dev/service/UserService.java | 129 ------- .../com/lions/dev/service/UsersService.java | 191 +++++++++++ 16 files changed, 1101 insertions(+), 196 deletions(-) create mode 100644 src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java create mode 100644 src/main/java/com/lions/dev/entity/friends/Friendship.java create mode 100644 src/main/java/com/lions/dev/entity/friends/FriendshipStatus.java create mode 100644 src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java create mode 100644 src/main/java/com/lions/dev/repository/FriendshipRepository.java create mode 100644 src/main/java/com/lions/dev/resource/FriendshipResource.java create mode 100644 src/main/java/com/lions/dev/service/FriendshipService.java delete mode 100644 src/main/java/com/lions/dev/service/UserService.java create mode 100644 src/main/java/com/lions/dev/service/UsersService.java diff --git a/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java index 4bdcf11..75bac61 100644 --- a/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java +++ b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java @@ -1,25 +1,53 @@ package com.lions.dev.core.errors; +import com.lions.dev.core.errors.exceptions.BadRequestException; import com.lions.dev.core.errors.exceptions.EventNotFoundException; +import com.lions.dev.core.errors.exceptions.NotFoundException; +import com.lions.dev.core.errors.exceptions.ServerException; +import com.lions.dev.core.errors.exceptions.UnauthorizedException; + import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; /** - * Gestionnaire global des exceptions pour mapper les exceptions à des réponses HTTP appropriées. + * Gestionnaire global des exceptions pour l'API. + * Ce gestionnaire intercepte les exceptions spécifiques et renvoie des réponses appropriées. */ @Provider -public class GlobalExceptionHandler implements ExceptionMapper { +public class GlobalExceptionHandler implements ExceptionMapper { + /** + * Gère les exceptions non traitées et retourne une réponse appropriée. + * + * @param exception L'exception interceptée. + * @return Une réponse HTTP avec un message d'erreur et le code de statut approprié. + */ @Override - public Response toResponse(Throwable exception) { - if (exception instanceof EventNotFoundException) { - return Response.status(Response.Status.NOT_FOUND) - .entity(exception.getMessage()) - .build(); + public Response toResponse(Exception exception) { + if (exception instanceof BadRequestException) { + return buildResponse(Response.Status.BAD_REQUEST, exception.getMessage()); + } else if (exception instanceof EventNotFoundException || exception instanceof NotFoundException) { + return buildResponse(Response.Status.NOT_FOUND, exception.getMessage()); + } else if (exception instanceof UnauthorizedException) { + return buildResponse(Response.Status.UNAUTHORIZED, exception.getMessage()); + } else if (exception instanceof ServerException) { + return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur interne du serveur."); } - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("Une erreur interne est survenue.") + + return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur inattendue : " + exception.getMessage()); + } + + /** + * Crée une réponse HTTP avec un code de statut et un message d'erreur. + * + * @param status Le code de statut HTTP. + * @param message Le message d'erreur. + * @return La réponse HTTP formée. + */ + private Response buildResponse(Response.Status status, String message) { + return Response.status(status) + .entity("{\"error\":\"" + message + "\"}") .build(); } } diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java b/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java index 14ddcb2..cf57486 100644 --- a/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java +++ b/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java @@ -18,4 +18,5 @@ public class BadRequestException extends WebApplicationException { super(message, Response.Status.BAD_REQUEST); System.out.println("[ERROR] Requête invalide : " + message); } + } diff --git a/src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java b/src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java new file mode 100644 index 0000000..9804d95 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java @@ -0,0 +1,25 @@ +package com.lions.dev.dto.request.friends; + +import lombok.Getter; +import lombok.Setter; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +/** + * DTO pour envoyer une demande d'amitié. + * Contient les informations nécessaires pour initier une demande d'amitié. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipRequestDTO { + + private UUID userId; // ID de l'utilisateur qui envoie la demande + private UUID friendId; // ID de l'utilisateur qui reçoit la demande + + public FriendshipRequestDTO(UUID userId, UUID friendId) { + this.userId = userId; + this.friendId = friendId; + } +} diff --git a/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java index d70ca3e..4e47ec9 100644 --- a/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/users/UserCreateRequestDTO.java @@ -31,6 +31,8 @@ public class UserCreateRequestDTO { @Size(min = 6, message = "Le mot de passe doit comporter au moins 6 caractères.") private String motDePasse; + private String profileImageUrl; + // Ajout du rôle avec validation @NotNull(message = "Le rôle est obligatoire.") private String role; // Rôle de l'utilisateur (par exemple : ADMIN, USER, etc.) diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java new file mode 100644 index 0000000..fe94d57 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java @@ -0,0 +1,57 @@ +package com.lions.dev.dto.response.friends; + +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO de réponse pour les demandes d'amitié par statut. + * Contient les informations essentielles sans données sensibles. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipRequestStatusResponseDTO { + + private UUID friendshipId; + private UUID userId; + private String userNom; + private String userPrenoms; + private UUID friendId; + private String friendNom; + private String friendPrenoms; + private FriendshipStatus status; + private LocalDateTime createdAt; + + public FriendshipRequestStatusResponseDTO(UUID friendshipId, UUID userId, String userNom, String userPrenoms, + UUID friendId, String friendNom, String friendPrenoms, + FriendshipStatus status, LocalDateTime createdAt) { + this.friendshipId = friendshipId; + this.userId = userId; + this.userNom = userNom; + this.userPrenoms = userPrenoms; + this.friendId = friendId; + this.friendNom = friendNom; + this.friendPrenoms = friendPrenoms; + this.status = status; + this.createdAt = createdAt; + } + + // Constructor to map directly from Friendship entity + public FriendshipRequestStatusResponseDTO(Friendship friendship) { + this.friendshipId = friendship.getId(); + this.userId = friendship.getUser().getId(); + this.userNom = friendship.getUser().getNom(); + this.userPrenoms = friendship.getUser().getPrenoms(); + this.friendId = friendship.getFriend().getId(); + this.friendNom = friendship.getFriend().getNom(); + this.friendPrenoms = friendship.getFriend().getPrenoms(); + this.status = friendship.getStatus(); + this.createdAt = friendship.getCreatedAt(); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java new file mode 100644 index 0000000..cfdbeca --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java @@ -0,0 +1,36 @@ +package com.lions.dev.dto.response.friends; + +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO de réponse pour une relation d'amitié. + * Contient les informations sur une relation d'amitié existante. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipResponseDTO { + + private UUID id; + private UUID userId; + private UUID friendId; + private FriendshipStatus status; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + + public FriendshipResponseDTO(Friendship friendship) { + this.id = friendship.getId(); + this.userId = friendship.getUser().getId(); + this.friendId = friendship.getFriend().getId(); + this.status = friendship.getStatus(); + this.createdAt = friendship.getCreatedAt(); + this.updatedAt = friendship.getUpdatedAt(); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java b/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java index fa47a31..7d3cf5f 100644 --- a/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/users/UserCreateResponseDTO.java @@ -16,7 +16,8 @@ public class UserCreateResponseDTO { private String nom; // Nom de l'utilisateur private String prenoms; // Prénoms de l'utilisateur private String email; // Email de l'utilisateur - + private String role; // Roğe de l'utilisateur + private String profileImageUrl; // Url de l'image de profil de l'utilisateur /** * Constructeur qui transforme une entité Users en DTO. * @@ -27,6 +28,8 @@ public class UserCreateResponseDTO { this.nom = user.getNom(); this.prenoms = user.getPrenoms(); this.email = user.getEmail(); + this.role = user.getRole(); + this.profileImageUrl = user.getProfileImageUrl(); System.out.println("[LOG] DTO créé pour l'utilisateur : " + this.email); } } diff --git a/src/main/java/com/lions/dev/entity/friends/Friendship.java b/src/main/java/com/lions/dev/entity/friends/Friendship.java new file mode 100644 index 0000000..4e0d126 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/friends/Friendship.java @@ -0,0 +1,54 @@ +package com.lions.dev.entity.friends; + +import com.lions.dev.entity.BaseEntity; // Import de BaseEntity +import com.lions.dev.entity.users.Users; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Représentation de l'entité Friendship qui gère les relations d'amitié entre utilisateurs. + */ +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +@Builder +@Table(name = "friendships") +public class Friendship extends BaseEntity { // Hérite de BaseEntity + + // L'utilisateur qui a initié la demande d'ami + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private Users user; + + // L'ami avec qui la relation est établie + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "friend_id", nullable = false) + private Users friend; + + // Statut de la relation (en attente, acceptée, rejetée) + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private FriendshipStatus status; + + /** + * Log des changements de statut de l'amitié. + */ + public void setStatus(FriendshipStatus newStatus) { + this.status = newStatus; + System.out.println( + "[LOG] Changement de statut pour l'amitié entre " + + this.user.getEmail() + + " et " + + this.friend.getEmail() + + " - Nouveau statut : " + + this.status); + } +} diff --git a/src/main/java/com/lions/dev/entity/friends/FriendshipStatus.java b/src/main/java/com/lions/dev/entity/friends/FriendshipStatus.java new file mode 100644 index 0000000..11c8316 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/friends/FriendshipStatus.java @@ -0,0 +1,7 @@ +package com.lions.dev.entity.friends; + +public enum FriendshipStatus { + PENDING, // Demande envoyée, en attente d'acceptation + ACCEPTED, // Demande acceptée + REJECTED // Demande rejetée +} \ No newline at end of file diff --git a/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java b/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java new file mode 100644 index 0000000..8f1a8ce --- /dev/null +++ b/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java @@ -0,0 +1,15 @@ +package com.lions.dev.exception; + +/** + * Exception levée lorsque la relation d'amitié n'est pas trouvée. + */ +public class FriendshipNotFoundException extends RuntimeException { + + public FriendshipNotFoundException(String message) { + super(message); + } + + public FriendshipNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/lions/dev/repository/FriendshipRepository.java b/src/main/java/com/lions/dev/repository/FriendshipRepository.java new file mode 100644 index 0000000..a06ccb5 --- /dev/null +++ b/src/main/java/com/lions/dev/repository/FriendshipRepository.java @@ -0,0 +1,80 @@ +package com.lions.dev.repository; + +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import com.lions.dev.entity.users.Users; +import io.quarkus.hibernate.orm.panache.PanacheRepository; +import jakarta.enterprise.context.ApplicationScoped; + +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. + */ +@ApplicationScoped +public class FriendshipRepository implements PanacheRepository { + + /** + * Trouve une relation d'amitié entre deux utilisateurs. + * + * @param user L'utilisateur qui envoie la demande. + * @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(); + } + + /** + * Récupère la liste des amis d'un utilisateur. + * + * @param user L'utilisateur dont on souhaite récupérer les amis. + * @return Une liste de relations d'amitié. + */ + public List findFriendsByUser(Users user, int page, int size) { + return find("(user = ?1 or friend = ?1) and status = ?2", user, FriendshipStatus.ACCEPTED) + .page(page, size) + .list(); + } + + /** + * Trouve une relation d'amitié par son ID. + * + * @param id L'ID de la relation d'amitié. + * @return Une Optional contenant la relation d'amitié, si elle existe. + */ + public Optional findById(UUID id) { + return find("id", id).firstResultOptional(); + } + + /** + * Supprime une relation d'amitié de la base de données. + * + * @param friendship La relation d'amitié à supprimer. + */ + public void deleteFriendship(Friendship friendship) { + if (friendship != null) { + this.delete(friendship); // Suppression de l'entité Friendship + System.out.println("[LOG] Entité Friendship supprimée : " + friendship.getId()); + } else { + System.out.println("[ERROR] Tentative de suppression d'une entité Friendship inexistante."); + } + } + + /** + * Récupère toutes les relations d'amitié d'un utilisateur ayant un statut particulier. + * + * @param user L'utilisateur dont on souhaite récupérer les amitiés. + * @param status Le statut des relations d'amitié à rechercher. + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'éléments par page. + * @return Une liste paginée de relations d'amitié ayant le statut spécifié pour cet utilisateur. + */ + public List findByUserAndStatus(Users user, FriendshipStatus status, int page, int size) { + return find("(user = ?1 or friend = ?1) and status = ?2", user, status) + .page(page, size) + .list(); + } +} diff --git a/src/main/java/com/lions/dev/resource/FriendshipResource.java b/src/main/java/com/lions/dev/resource/FriendshipResource.java new file mode 100644 index 0000000..6e18fe0 --- /dev/null +++ b/src/main/java/com/lions/dev/resource/FriendshipResource.java @@ -0,0 +1,317 @@ +package com.lions.dev.resource; + +import com.lions.dev.dto.request.friends.FriendshipRequestDTO; +import com.lions.dev.dto.response.friends.FriendshipRequestStatusResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipResponseDTO; +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.UsersRepository; +import com.lions.dev.service.FriendshipService; +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.util.List; +import java.util.UUID; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.jboss.logging.Logger; + +/** + * Ressource REST pour gérer les amitiés. Ce contrôleur expose des endpoints pour envoyer, accepter, + * rejeter et supprimer des demandes d'amitié. Les opérations sont loguées pour suivre leur + * déroulement en temps réel. + */ +@Path("/friends") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Tag(name = "Friendship", description = "Opérations liées à la gestion des amis") +public class FriendshipResource { + + @Inject + FriendshipService friendshipService; + + @Inject + UsersRepository usersRepository; + + private static final Logger logger = Logger.getLogger(FriendshipResource.class); + + /** + * Envoie une demande d'amitié. + * + * @param request DTO contenant l'ID de l'utilisateur qui reçoit la demande. + * @return La relation d'amitié créée. + */ + @POST + @Path("/send") + @Operation( + summary = "Envoyer une demande d'amitié", + description = "Envoie une demande d'amitié d'un utilisateur à un autre") + @APIResponses({ + @APIResponse( + responseCode = "200", + description = "Demande d'amitié envoyée", + content = + @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FriendshipResponseDTO.class))), + @APIResponse(responseCode = "400", description = "Requête invalide"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Response sendFriendRequest(@Valid @NotNull FriendshipRequestDTO request) { + logger.info( + "[LOG] Reçu une demande pour envoyer une demande d'amitié de l'utilisateur " + + request.getUserId() + + " à l'utilisateur " + + request.getFriendId()); + + try { + Friendship friendship = + friendshipService.sendFriendRequest(request.getUserId(), request.getFriendId()); + logger.info( + "[LOG] Demande d'amitié envoyée avec succès : " + + friendship.getUser().getEmail() + + " à " + + friendship.getFriend().getEmail()); + return Response.ok(new FriendshipResponseDTO(friendship)).build(); + } catch (Exception e) { + logger.error("[ERROR] Erreur lors de l'envoi de la demande d'amitié : " + e.getMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de l'envoi de la demande d'amitié.\"}") + .build(); + } + } + + /** + * Accepte une demande d'amitié. + * + * @param friendshipId L'ID de la relation d'amitié à accepter. + * @return La relation d'amitié acceptée. + */ + @PATCH + @Path("/{friendshipId}/accept") + @Operation( + summary = "Accepter une demande d'amitié", + description = "Accepte une demande d'amitié en attente") + @APIResponses({ + @APIResponse( + responseCode = "200", + description = "Demande d'amitié acceptée", + content = + @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FriendshipResponseDTO.class))), + @APIResponse(responseCode = "404", description = "Demande d'amitié non trouvée"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Response acceptFriendRequest(@PathParam("friendshipId") UUID friendshipId) { + logger.info( + "[LOG] Reçu une demande pour accepter une demande d'amitié avec l'ID : " + friendshipId); + + try { + Friendship friendship = friendshipService.acceptFriendRequest(friendshipId); + logger.info( + "[LOG] Demande d'amitié acceptée entre " + + friendship.getUser().getEmail() + + " et " + + friendship.getFriend().getEmail()); + return Response.ok(new FriendshipResponseDTO(friendship)).build(); + } catch (NotFoundException e) { + logger.error("[ERROR] Demande d'amitié non trouvée : " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Demande d'amitié non trouvée.\"}") + .build(); + } catch (Exception e) { + logger.error( + "[ERROR] Erreur lors de l'acceptation de la demande d'amitié : " + e.getMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de l'acceptation de la demande d'amitié.\"}") + .build(); + } + } + + /** + * Rejette une demande d'amitié. + * + * @param friendshipId L'ID de la relation d'amitié à rejeter. + * @return Confirmation de la demande rejetée. + */ + @PATCH + @Path("/{friendshipId}/reject") + @Operation( + summary = "Rejeter une demande d'amitié", + description = "Rejette une demande d'amitié en attente") + @APIResponses({ + @APIResponse(responseCode = "204", description = "Demande d'amitié rejetée"), + @APIResponse(responseCode = "404", description = "Demande d'amitié non trouvée"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Response rejectFriendRequest(@PathParam("friendshipId") UUID friendshipId) { + logger.info( + "[LOG] Reçu une demande pour rejeter une demande d'amitié avec l'ID : " + friendshipId); + + try { + friendshipService.rejectFriendRequest(friendshipId); + logger.info("[LOG] Demande d'amitié rejetée pour l'ID : " + friendshipId); + return Response.noContent().build(); + } catch (NotFoundException e) { + logger.error("[ERROR] Demande d'amitié non trouvée : " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Demande d'amitié non trouvée.\"}") + .build(); + } catch (Exception e) { + logger.error("[ERROR] Erreur lors du rejet de la demande d'amitié : " + e.getMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors du rejet de la demande d'amitié.\"}") + .build(); + } + } + + /** + * Supprime une relation d'amitié. + * + * @param friendshipId L'ID de la relation d'amitié à supprimer. + * @return Confirmation de la suppression. + */ + @DELETE + @Path("/{friendshipId}") + @Operation( + summary = "Supprimer une relation d'amitié", + description = "Supprime une relation d'amitié existante") + @APIResponses({ + @APIResponse(responseCode = "204", description = "Relation d'amitié supprimée"), + @APIResponse(responseCode = "404", description = "Relation d'amitié non trouvée"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Response removeFriend(@PathParam("friendshipId") UUID friendshipId) { + logger.info( + "[LOG] Reçu une demande pour supprimer la relation d'amitié avec l'ID : " + friendshipId); + + try { + friendshipService.removeFriend(friendshipId); + logger.info("[LOG] Relation d'amitié supprimée avec succès pour l'ID : " + friendshipId); + return Response.noContent().build(); + } catch (NotFoundException e) { + logger.error("[ERROR] Relation d'amitié non trouvée : " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Relation d'amitié non trouvée.\"}") + .build(); + } catch (Exception e) { + logger.error( + "[ERROR] Erreur lors de la suppression de la relation d'amitié : " + e.getMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de la suppression de la relation d'amitié.\"}") + .build(); + } + } + + /** + * Récupère la liste des amis d'un utilisateur. + * + * @param userId L'ID de l'utilisateur dont on veut récupérer les amis. + * @param page Numéro de la page pour la pagination. + * @param size Nombre d'éléments par page. + * @return La liste des amis de l'utilisateur. + */ + @GET + @Path("/list/{userId}") + @Operation( + summary = "Lister les amis d'un utilisateur", + description = "Récupère la liste de tous les amis d'un utilisateur donné") + @APIResponses({ + @APIResponse( + responseCode = "200", + description = "Liste des amis récupérée", + content = + @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = + @Schema( + type = SchemaType.ARRAY, + implementation = FriendshipResponseDTO.class))), + @APIResponse(responseCode = "404", description = "Utilisateur non trouvé"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Response listFriends( + @PathParam("userId") UUID userId, + @QueryParam("page") @DefaultValue("1") int page, + @QueryParam("size") @DefaultValue("10") int size) { + logger.info( + "[LOG] Reçu une demande pour récupérer la liste des amis de l'utilisateur avec l'ID : " + + userId); + + try { + List friends = friendshipService.listFriends(userId, page, size); + logger.info( + "[LOG] Liste des amis récupérée avec succès pour l'utilisateur " + + userId + + ", nombre d'amis : " + + friends.size()); + return Response.ok(friends.stream().map(FriendshipResponseDTO::new)).build(); + } catch (NotFoundException e) { + logger.error("[ERROR] Utilisateur non trouvé : " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Utilisateur non trouvé.\"}") + .build(); + } catch (Exception e) { + logger.error( + "[ERROR] Erreur lors de la récupération de la liste des amis : " + e.getMessage()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de la récupération de la liste des amis.\"}") + .build(); + } + } + + /** + * Endpoint pour récupérer les demandes d'amitié avec un statut spécifique. + * + * @param userId L'ID de l'utilisateur. + * @param status Le statut des demandes à filtrer (PENDING, ACCEPTED, REJECTED). + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'éléments par page. + * @return La liste paginée des demandes d'amitié avec le statut spécifié. + */ + @GET + @Path("/status") + @Operation( + summary = "Récupérer les demandes d'amitié faites par un utilisateur par statut", + description = "Retourne la liste des demandes d'amitié faites par un utilisateur avec un " + + "statut particulier.") + public Response listFriendRequestsByStatus( + @QueryParam("userId") UUID userId, + @QueryParam("status") FriendshipStatus status, + @QueryParam("page") @DefaultValue("1") int page, + @QueryParam("size") @DefaultValue("10") int size) { + + logger.info("[LOG] Récupération des demandes d'amitié avec le statut : " + status); + + // Récupère l'utilisateur à partir de l'ID fourni + Users user = usersRepository.findById(userId); + if (user == null) { + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Utilisateur non trouvé.\"}") + .build(); + } + + // Ajuste la pagination (Panache commence à 0) + int adjustedPage = page - 1; + if (adjustedPage < 0) adjustedPage = 0; + + List friendships = friendshipService.listFriendRequestsByStatus(user, status, adjustedPage, size); + + // Transformation des entités Friendship en DTOs adaptés + List responseDTOs = friendships.stream() + .map(FriendshipRequestStatusResponseDTO::new) + .toList(); + + return Response.ok(responseDTOs).build(); + } +} diff --git a/src/main/java/com/lions/dev/resource/UsersResource.java b/src/main/java/com/lions/dev/resource/UsersResource.java index 3680539..934a1a5 100644 --- a/src/main/java/com/lions/dev/resource/UsersResource.java +++ b/src/main/java/com/lions/dev/resource/UsersResource.java @@ -1,37 +1,39 @@ package com.lions.dev.resource; -import java.io.File; - -import jakarta.ws.rs.Path; import com.lions.dev.dto.request.users.UserAuthenticateRequestDTO; +import com.lions.dev.dto.request.users.UserCreateRequestDTO; import com.lions.dev.dto.response.users.UserAuthenticateResponseDTO; +import com.lions.dev.dto.response.users.UserCreateResponseDTO; import com.lions.dev.dto.response.users.UserDeleteResponseDto; import com.lions.dev.entity.users.Users; -import com.lions.dev.service.UserService; +import com.lions.dev.service.UsersService; import jakarta.inject.Inject; import jakarta.transaction.Transactional; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import java.io.File; +import java.util.List; import java.util.UUID; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; - /** - * Ressource REST pour la gestion des utilisateurs dans le système AfterWork. Cette classe expose - * des endpoints pour créer, authentifier, récupérer et supprimer des utilisateurs. - * - *

Tous les logs nécessaires pour la traçabilité sont intégrés. + * Ressource REST pour la gestion des utilisateurs dans le système AfterWork. + * Cette classe expose des endpoints pour créer, authentifier, récupérer et supprimer des utilisateurs. + * Tous les logs nécessaires pour la traçabilité sont intégrés. */ @Path("/users") -@Produces("application/json") -@Consumes("application/json") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) @Tag(name = "Users", description = "Opérations liées à la gestion des utilisateurs") public class UsersResource { @Inject - UserService userService; + UsersService userService; private static final Logger LOG = Logger.getLogger(UsersResource.class); @@ -46,17 +48,13 @@ public class UsersResource { @Operation( summary = "Créer un nouvel utilisateur", description = "Crée un nouvel utilisateur et retourne les détails") - public Response createUser( - com.lions.dev.dto.request.users.UserCreateRequestDTO userCreateRequestDTO) { + public Response createUser(@Valid @NotNull UserCreateRequestDTO userCreateRequestDTO) { LOG.info( "Tentative de création d'un nouvel utilisateur avec l'email : " + userCreateRequestDTO.getEmail()); - // Utilisation de UserService pour créer l'utilisateur Users user = userService.createUser(userCreateRequestDTO); - - com.lions.dev.dto.response.users.UserCreateResponseDTO - responseDTO = new com.lions.dev.dto.response.users.UserCreateResponseDTO(user); + UserCreateResponseDTO responseDTO = new UserCreateResponseDTO(user); return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } @@ -71,25 +69,14 @@ public class UsersResource { @Operation( summary = "Authentifier un utilisateur", description = "Vérifie les informations de connexion de l'utilisateur") - public Response authenticateUser(UserAuthenticateRequestDTO userAuthenticateRequestDTO) { - LOG.info( - "Tentative d'authentification pour l'utilisateur avec l'email : " - + userAuthenticateRequestDTO.getEmail()); - - // Utilisation de UserService pour authentifier l'utilisateur - Users user = - userService.authenticateUser( - userAuthenticateRequestDTO.getEmail(), userAuthenticateRequestDTO.getMotDePasse()); + public Response authenticateUser(@Valid @NotNull UserAuthenticateRequestDTO userAuthenticateRequestDTO) { + LOG.info("Tentative d'authentification pour l'utilisateur avec l'email : " + userAuthenticateRequestDTO.getEmail()); + Users user = userService.authenticateUser(userAuthenticateRequestDTO.getEmail(), userAuthenticateRequestDTO.getMotDePasse()); LOG.info("Authentification réussie pour l'utilisateur : " + user.getEmail()); - // Création du DTO de réponse avec les informations supplémentaires de l'utilisateur - UserAuthenticateResponseDTO responseDTO = - new UserAuthenticateResponseDTO( - user.getId(), user.getPrenoms(), user.getNom(), user.getEmail(), user.getRole()); - + UserAuthenticateResponseDTO responseDTO = new UserAuthenticateResponseDTO(user.getId(), user.getPrenoms(), user.getNom(), user.getEmail(), user.getRole()); responseDTO.logResponseDetails(); - return Response.ok(responseDTO).build(); } @@ -107,15 +94,31 @@ public class UsersResource { public Response getUserById(@PathParam("id") UUID id) { LOG.info("Récupération de l'utilisateur avec l'ID : " + id); - // Utilisation de UserService pour récupérer l'utilisateur Users user = userService.getUserById(id); - - com.lions.dev.dto.response.users.UserCreateResponseDTO - responseDTO = new com.lions.dev.dto.response.users.UserCreateResponseDTO(user); + UserCreateResponseDTO responseDTO = new UserCreateResponseDTO(user); LOG.info("Utilisateur trouvé : " + user.getEmail()); return Response.ok(responseDTO).build(); } + /** + * Endpoint pour récupérer tous les utilisateurs avec pagination. + * + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'utilisateurs par page. + * @return Une réponse HTTP contenant la liste des utilisateurs paginée. + */ + @GET + @Operation( + summary = "Récupérer tous les utilisateurs avec pagination", + description = "Retourne la liste paginée des utilisateurs") + public Response listUsers(@QueryParam("page") @DefaultValue("1") int page, @QueryParam("size") @DefaultValue("10") int size) { + LOG.info("Récupération de la liste des utilisateurs - page : " + page + ", taille : " + size); + + List users = userService.listUsers(page, size); + LOG.info("Liste des utilisateurs récupérée avec succès, taille : " + users.size()); + return Response.ok(users).build(); + } + /** * Endpoint pour supprimer un utilisateur par ID. * @@ -131,7 +134,6 @@ public class UsersResource { public Response deleteUser(@PathParam("id") UUID id) { LOG.info("Tentative de suppression de l'utilisateur avec l'ID : " + id); - // Utilisation de UserService pour supprimer l'utilisateur boolean deleted = userService.deleteUser(id); UserDeleteResponseDto responseDTO = new UserDeleteResponseDto(); @@ -150,6 +152,50 @@ public class UsersResource { } } + /** + * Endpoint pour mettre à jour un utilisateur. + * + * @param id L'ID de l'utilisateur à mettre à jour. + * @param userCreateRequestDTO Les informations mises à jour de l'utilisateur. + * @return Les informations de l'utilisateur mis à jour. + */ + @PUT + @Path("/{id}") + @Transactional + @Operation( + summary = "Mettre à jour un utilisateur", + description = "Met à jour les informations d'un utilisateur existant") + public Response updateUser(@PathParam("id") UUID id, @Valid UserCreateRequestDTO userCreateRequestDTO) { + LOG.info("Tentative de mise à jour de l'utilisateur avec l'ID : " + id); + + // Appel au service avec l'ID et les nouvelles informations + Users updatedUser = userService.updateUser(id, userCreateRequestDTO); + + LOG.info("Utilisateur mis à jour avec succès : " + updatedUser.getEmail()); + UserCreateResponseDTO responseDTO = new UserCreateResponseDTO(updatedUser); + return Response.ok(responseDTO).build(); + } + + /** + * Endpoint pour réinitialiser le mot de passe d'un utilisateur. + * + * @param id L'ID de l'utilisateur. + * @param nouveauMotDePasse Le nouveau mot de passe. + * @return Un message indiquant si la réinitialisation a réussi. + */ + @PATCH + @Path("/{id}/reset-password") + @Transactional + @Operation( + summary = "Réinitialiser le mot de passe d'un utilisateur", + description = "Réinitialise le mot de passe de l'utilisateur et le met à jour dans la base de données") + public Response resetPassword(@PathParam("id") UUID id, @QueryParam("newPassword") String nouveauMotDePasse) { + LOG.info("Réinitialisation du mot de passe pour l'utilisateur avec l'ID : " + id); + + userService.resetPassword(id, nouveauMotDePasse); + return Response.ok("{\"message\": \"Mot de passe réinitialisé avec succès.\"}").build(); + } + /** * Endpoint pour mettre à jour l'image de profil de l'utilisateur. * @@ -158,37 +204,25 @@ public class UsersResource { * @return Un message indiquant si la mise à jour a réussi. */ @PUT - @jakarta.ws.rs.Path("/{id}/profile-image") // Annotation REST avec jakarta.ws.rs.Path + @Path("/{id}/profile-image") + @Operation(summary = "Mettre à jour l'image de profil d'un utilisateur", description = "Met à jour l'image de profil d'un utilisateur.") public String updateUserProfileImage(@PathParam("id") UUID id, String imageFilePath) { try { - // Utiliser File au lieu de Path pour vérifier si le fichier existe File file = new File(imageFilePath); if (!file.exists()) { - System.out.println("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); + LOG.error("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); return "Le fichier spécifié n'existe pas."; } - // Récupérer l'utilisateur par son ID - Users user = userService.getUserById(id); - if (user == null) { - System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); - return "Utilisateur non trouvé."; - } - - // Mettre à jour l'URL de l'image de profil - String profileImageUrl = file.getAbsolutePath(); // Obtenir le chemin complet du fichier - user.setProfileImageUrl(profileImageUrl); - - // Mise à jour de l'utilisateur - userService.updateUser(user); - System.out.println("[LOG] Image de profil mise à jour pour l'utilisateur : " + user.getEmail()); + String profileImageUrl = file.getAbsolutePath(); + userService.updateUserProfileImage(id, profileImageUrl); // Appel à la méthode correcte + LOG.info("[LOG] Image de profil mise à jour pour l'utilisateur avec l'ID : " + id); return "Image de profil mise à jour avec succès."; } catch (Exception e) { - System.out.println("[ERROR] Erreur lors de la mise à jour de l'image de profil : " + e.getMessage()); + LOG.error("[ERROR] Erreur lors de la mise à jour de l'image de profil : " + e.getMessage()); return "Erreur lors de la mise à jour de l'image de profil."; } } - } diff --git a/src/main/java/com/lions/dev/service/FriendshipService.java b/src/main/java/com/lions/dev/service/FriendshipService.java new file mode 100644 index 0000000..d8b11ae --- /dev/null +++ b/src/main/java/com/lions/dev/service/FriendshipService.java @@ -0,0 +1,184 @@ +package com.lions.dev.service; + +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import com.lions.dev.entity.users.Users; +import com.lions.dev.exception.FriendshipNotFoundException; +import com.lions.dev.exception.UserNotFoundException; +import com.lions.dev.repository.FriendshipRepository; +import com.lions.dev.repository.UsersRepository; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Service de gestion des amitiés. Ce service gère l'envoi, l'acceptation, le rejet et la + * suppression d'amitiés. + */ +@ApplicationScoped +public class FriendshipService { + + @Inject FriendshipRepository friendshipRepository; + + @Inject UsersRepository usersRepository; + + /** + * Envoie une demande d'amitié entre deux utilisateurs. + * + * @param userId L'ID de l'utilisateur qui envoie la demande. + * @param friendId L'ID de l'utilisateur qui reçoit la demande. + * @return La relation d'amitié créée. + * @throws UserNotFoundException Si l'un des utilisateurs n'est pas trouvé. + */ + @Transactional + public Friendship sendFriendRequest(UUID userId, UUID friendId) { + System.out.println( + "[LOG] Envoi de demande d'amitié de l'utilisateur " + + userId + + " à l'utilisateur " + + friendId); + + Users user = usersRepository.findById(userId); + Users friend = usersRepository.findById(friendId); + + if (user == null || friend == null) { + System.out.println( + "[ERROR] Utilisateur non trouvé pour l'ID : " + (user == null ? userId : friendId)); + throw new UserNotFoundException("L'utilisateur avec l'ID spécifié n'existe pas."); + } + + Optional existingFriendship = friendshipRepository.findByUsers(user, friend); + if (existingFriendship.isPresent()) { + System.out.println("[ERROR] Une relation d'amitié existe déjà entre ces deux utilisateurs."); + throw new IllegalArgumentException("Relation d'amitié déjà existante."); + } + + Friendship friendship = + Friendship.builder().user(user).friend(friend).status(FriendshipStatus.PENDING).build(); + + friendshipRepository.persist(friendship); + System.out.println( + "[LOG] Demande d'amitié envoyée de " + user.getEmail() + " à " + friend.getEmail()); + + return friendship; + } + + /** + * Accepte une demande d'amitié. + * + * @param friendshipId L'ID de la demande d'amitié. + * @return La relation d'amitié acceptée. + * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + */ + @Transactional + public Friendship acceptFriendRequest(UUID friendshipId) { + System.out.println("[LOG] Acceptation de la demande d'amitié avec l'ID : " + friendshipId); + + Friendship friendship = + friendshipRepository + .findById(friendshipId) + .orElseThrow(() -> new FriendshipNotFoundException("Demande d'amitié introuvable.")); + + if (friendship.getStatus() == FriendshipStatus.ACCEPTED) { + System.out.println("[ERROR] La demande d'amitié a déjà été acceptée."); + throw new IllegalArgumentException("Cette demande d'amitié a déjà été acceptée."); + } + + friendship.setStatus(FriendshipStatus.ACCEPTED); + friendshipRepository.persist(friendship); + System.out.println( + "[LOG] Demande d'amitié acceptée entre " + + friendship.getUser().getEmail() + + " et " + + friendship.getFriend().getEmail()); + + return friendship; + } + + /** + * Rejette une demande d'amitié. + * + * @param friendshipId L'ID de la demande d'amitié. + * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + */ + @Transactional + public void rejectFriendRequest(UUID friendshipId) { + System.out.println("[LOG] Rejet de la demande d'amitié avec l'ID : " + friendshipId); + + Friendship friendship = + friendshipRepository + .findById(friendshipId) + .orElseThrow(() -> new FriendshipNotFoundException("Demande d'amitié introuvable.")); + + friendship.setStatus(FriendshipStatus.REJECTED); + friendshipRepository.persist(friendship); + System.out.println( + "[LOG] Demande d'amitié rejetée entre " + + friendship.getUser().getEmail() + + " et " + + friendship.getFriend().getEmail()); + } + + /** + * Supprime une relation d'amitié. + * + * @param friendshipId L'ID de la relation d'amitié à supprimer. + * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + */ + @Transactional + public void removeFriend(UUID friendshipId) { + System.out.println("[LOG] Suppression de la relation d'amitié avec l'ID : " + friendshipId); + + Friendship friendship = + friendshipRepository + .findById(friendshipId) + .orElseThrow(() -> new FriendshipNotFoundException("Amitié introuvable.")); + + friendshipRepository.deleteFriendship(friendship); // Appel à deleteFriendship + System.out.println( + "[LOG] Amitié supprimée entre " + + friendship.getUser().getEmail() + + " et " + + friendship.getFriend().getEmail()); + } + + /** + * Récupère la liste des amis d'un utilisateur avec pagination. + * + * @param userId L'ID de l'utilisateur. + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'éléments par page. + * @return La liste paginée des relations d'amitié. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + public List listFriends(UUID userId, int page, int size) { + System.out.println( + "[LOG] Récupération de la liste paginée des amis pour l'utilisateur avec l'ID : " + userId); + + Users user = usersRepository.findById(userId); + if (user == null) { + System.out.println("[ERROR] Utilisateur non trouvé pour l'ID : " + userId); + throw new UserNotFoundException("Utilisateur non trouvé."); + } + + return friendshipRepository.findFriendsByUser(user, page, size); + } + + /** + * Récupère toutes les demandes d'amitié avec un statut spécifique. + * + * @param user L'utilisateur. + * @param status Le statut des demandes d'amitié à récupérer (PENDING, ACCEPTED, REJECTED). + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'éléments par page. + * @return La liste paginée des relations d'amitié avec le statut spécifié. + */ + public List listFriendRequestsByStatus(Users user, FriendshipStatus status, int page, int size) { + System.out.println("[LOG] Récupération des demandes d'amitié avec le statut : " + status); + return friendshipRepository.findByUserAndStatus(user, status, page, size); + } + +} diff --git a/src/main/java/com/lions/dev/service/UserService.java b/src/main/java/com/lions/dev/service/UserService.java deleted file mode 100644 index 15f920d..0000000 --- a/src/main/java/com/lions/dev/service/UserService.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.lions.dev.service; - -import com.lions.dev.entity.users.Users; -import com.lions.dev.repository.UsersRepository; -import com.lions.dev.exception.UserNotFoundException; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import java.util.Optional; -import java.util.UUID; - -/** - * Service de gestion des utilisateurs. - * Ce service contient la logique métier pour la création, récupération et suppression des utilisateurs. - */ -@ApplicationScoped -public class UserService { - - @Inject - UsersRepository usersRepository; - - /** - * Crée un nouvel utilisateur dans le système. - * - * @param userCreateRequestDTO Le DTO contenant les informations de l'utilisateur à créer. - * @return L'utilisateur créé. - */ - public Users createUser(com.lions.dev.dto.request.users.UserCreateRequestDTO userCreateRequestDTO) { - Users user = new Users(); - user.setNom(userCreateRequestDTO.getNom()); - user.setPrenoms(userCreateRequestDTO.getPrenoms()); - user.setEmail(userCreateRequestDTO.getEmail()); - user.setMotDePasse(userCreateRequestDTO.getMotDePasse()); // Hachage automatique - - // Vérifier si le rôle est défini, sinon attribuer un rôle par défaut - if (userCreateRequestDTO.getRole() == null || userCreateRequestDTO.getRole().isEmpty()) { - user.setRole("USER"); // Assigner un rôle par défaut, par exemple "USER" - } else { - user.setRole(userCreateRequestDTO.getRole()); - } - - usersRepository.persist(user); - System.out.println("[LOG] Utilisateur créé : " + user.getEmail()); - return user; - } - - /** - * Met à jour un utilisateur existant dans le système. - * - * @param user L'utilisateur à mettre à jour. - * @return L'utilisateur mis à jour. - */ - public Users updateUser(Users user) { - try { - Users existingUser = usersRepository.findById(user.getId()); - if (existingUser == null) { - System.out.println("[ERROR] Utilisateur non trouvé pour la mise à jour avec l'ID : " + user.getId()); - throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + user.getId()); - } - - // Mettre à jour les champs de l'utilisateur existant - existingUser.setNom(user.getNom()); - existingUser.setPrenoms(user.getPrenoms()); - existingUser.setEmail(user.getEmail()); - existingUser.setMotDePasse(user.getMotDePasse()); // Hachage automatique si nécessaire - existingUser.setRole(user.getRole()); - - usersRepository.persist(existingUser); - System.out.println("[LOG] Utilisateur mis à jour avec succès : " + existingUser.getEmail()); - return existingUser; - } catch (Exception e) { - System.out.println("[ERROR] Erreur lors de la mise à jour de l'utilisateur : " + e.getMessage()); - throw e; - } - } - - - /** - * Authentifie un utilisateur avec son email et son mot de passe. - * - * @param email L'email de l'utilisateur. - * @param motDePasse Le mot de passe de l'utilisateur. - * @return L'utilisateur authentifié. - * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé ou si le mot de passe est incorrect. - */ - public Users authenticateUser(String email, String motDePasse) { - Optional userOptional = usersRepository.findByEmail(email); - if (userOptional.isEmpty() || !userOptional.get().verifierMotDePasse(motDePasse)) { - System.out.println("[ERROR] Échec de l'authentification pour l'email : " + email); - throw new UserNotFoundException("Utilisateur ou mot de passe incorrect."); - } - System.out.println("[LOG] Utilisateur authentifié : " + email); - return userOptional.get(); - } - - /** - * Récupère un utilisateur par son ID. - * - * @param id L'ID de l'utilisateur. - * @return L'utilisateur trouvé. - * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. - */ - public Users getUserById(UUID id) { - Users user = usersRepository.findById(id); - if (user == null) { - System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); - throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + id); - } - System.out.println("[LOG] Utilisateur trouvé avec l'ID : " + id); - return user; - } - - /** - * Supprime un utilisateur par son ID. - * - * @param id L'ID de l'utilisateur à supprimer. - * @return true si l'utilisateur a été supprimé, false sinon. - */ - public boolean deleteUser(UUID id) { - boolean deleted = usersRepository.deleteById(id); - if (deleted) { - System.out.println("[LOG] Utilisateur supprimé avec succès : " + id); - } else { - System.out.println("[ERROR] Échec de la suppression de l'utilisateur avec l'ID : " + id); - } - return deleted; - } - - -} diff --git a/src/main/java/com/lions/dev/service/UsersService.java b/src/main/java/com/lions/dev/service/UsersService.java new file mode 100644 index 0000000..21678be --- /dev/null +++ b/src/main/java/com/lions/dev/service/UsersService.java @@ -0,0 +1,191 @@ +package com.lions.dev.service; + +import com.lions.dev.dto.request.users.UserCreateRequestDTO; +import com.lions.dev.entity.users.Users; +import com.lions.dev.exception.UserNotFoundException; +import com.lions.dev.repository.UsersRepository; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Service de gestion des utilisateurs. + * Ce service contient la logique métier pour la création, récupération et suppression des utilisateurs. + */ +@ApplicationScoped +public class UsersService { + + @Inject + UsersRepository usersRepository; + + /** + * Crée un nouvel utilisateur dans le système. + * + * @param userCreateRequestDTO Le DTO contenant les informations de l'utilisateur à créer. + * @return L'utilisateur créé. + */ + public Users createUser(UserCreateRequestDTO userCreateRequestDTO) { + Users user = new Users(); + user.setNom(userCreateRequestDTO.getNom()); + user.setPrenoms(userCreateRequestDTO.getPrenoms()); + user.setEmail(userCreateRequestDTO.getEmail()); + user.setMotDePasse(userCreateRequestDTO.getMotDePasse()); // Hachage automatique + + // Vérifier si le profile image est défini, sinon attribuer une image par défaut + if (userCreateRequestDTO.getProfileImageUrl() == null + || userCreateRequestDTO.getProfileImageUrl().isEmpty()) { + user.setProfileImageUrl("https://via.placeholder.com/150"); // Assigner une image par défaut + } else { + user.setProfileImageUrl(userCreateRequestDTO.getProfileImageUrl()); + } + + // Vérifier si le rôle est défini, sinon attribuer un rôle par défaut + if (userCreateRequestDTO.getRole() == null || userCreateRequestDTO.getRole().isEmpty()) { + user.setRole("USER"); // Assigner un rôle par défaut + } else { + user.setRole(userCreateRequestDTO.getRole()); + } + + usersRepository.persist(user); + System.out.println("[LOG] Utilisateur créé : " + user.getEmail()); + return user; + } + + /** + * Met à jour un utilisateur existant dans le système. + * + * @param id L'ID de l'utilisateur à mettre à jour. + * @param userCreateRequestDTO Les nouvelles informations de l'utilisateur. + * @return L'utilisateur mis à jour. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + @Transactional + public Users updateUser(UUID id, UserCreateRequestDTO userCreateRequestDTO) { + Users existingUser = usersRepository.findById(id); + if (existingUser == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + id); + } + + // Mettre à jour les champs de l'utilisateur existant + existingUser.setNom(userCreateRequestDTO.getNom()); + existingUser.setPrenoms(userCreateRequestDTO.getPrenoms()); + existingUser.setEmail(userCreateRequestDTO.getEmail()); + existingUser.setMotDePasse(userCreateRequestDTO.getMotDePasse()); // Hachage automatique si nécessaire + existingUser.setRole(userCreateRequestDTO.getRole()); + existingUser.setProfileImageUrl(userCreateRequestDTO.getProfileImageUrl()); + + usersRepository.persist(existingUser); + System.out.println("[LOG] Utilisateur mis à jour avec succès : " + existingUser.getEmail()); + return existingUser; + } + /** + * Met à jour l'image de profil d'un utilisateur existant dans le système. + * + * @param id L'ID de l'utilisateur à mettre à jour. + * @param profileImageUrl Les nouvelles informations de l'utilisateur. + * @return L'utilisateur mis à jour. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + @Transactional + public Users updateUserProfileImage(UUID id, String profileImageUrl) { + Users existingUser = usersRepository.findById(id); + if (existingUser == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + id); + } + + // Mettre à jour les champs de l'utilisateur existant + existingUser.setProfileImageUrl(profileImageUrl); + + usersRepository.persist(existingUser); + System.out.println("[LOG] L'image de profile de l\'Utilisateur mis à jour avec succès : " + existingUser.getEmail()); + return existingUser; + } + + /** + * Liste tous les utilisateurs avec pagination. + * + * @param page Le numéro de la page à récupérer. + * @param size Le nombre d'utilisateurs par page. + * @return La liste des utilisateurs paginée. + */ + public List listUsers(int page, int size) { + return usersRepository.findAll().page(page - 1, size).list(); + } + + /** + * Authentifie un utilisateur avec son email et son mot de passe. + * + * @param email L'email de l'utilisateur. + * @param motDePasse Le mot de passe de l'utilisateur. + * @return L'utilisateur authentifié. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé ou si le mot de passe est incorrect. + */ + public Users authenticateUser(String email, String motDePasse) { + Optional userOptional = usersRepository.findByEmail(email); + if (userOptional.isEmpty() || !userOptional.get().verifierMotDePasse(motDePasse)) { + System.out.println("[ERROR] Échec de l'authentification pour l'email : " + email); + throw new UserNotFoundException("Utilisateur ou mot de passe incorrect."); + } + System.out.println("[LOG] Utilisateur authentifié : " + email); + return userOptional.get(); + } + + /** + * Récupère un utilisateur par son ID. + * + * @param id L'ID de l'utilisateur. + * @return L'utilisateur trouvé. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + public Users getUserById(UUID id) { + Users user = usersRepository.findById(id); + if (user == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + id); + } + System.out.println("[LOG] Utilisateur trouvé avec l'ID : " + id); + return user; + } + + /** + * Réinitialise le mot de passe d'un utilisateur. + * + * @param id L'ID de l'utilisateur. + * @param newPassword Le nouveau mot de passe à définir. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + @Transactional + public void resetPassword(UUID id, String newPassword) { + Users user = usersRepository.findById(id); + if (user == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + throw new UserNotFoundException("Utilisateur non trouvé."); + } + + user.setMotDePasse(newPassword); // Hachage automatique + usersRepository.persist(user); + System.out.println("[LOG] Mot de passe réinitialisé pour l'utilisateur : " + user.getEmail()); + } + + /** + * Supprime un utilisateur par son ID. + * + * @param id L'ID de l'utilisateur à supprimer. + * @return true si l'utilisateur a été supprimé, false sinon. + */ + public boolean deleteUser(UUID id) { + boolean deleted = usersRepository.deleteById(id); + if (deleted) { + System.out.println("[LOG] Utilisateur supprimé avec succès : " + id); + } else { + System.out.println("[ERROR] Échec de la suppression de l'utilisateur avec l'ID : " + id); + } + return deleted; + } +} From 841789f8c2bc31e86f291a9bb2c22a294dd24201 Mon Sep 17 00:00:00 2001 From: DahoudG Date: Sat, 2 Nov 2024 15:27:03 +0000 Subject: [PATCH 6/8] Refactoring --- .../core/errors/GlobalExceptionHandler.java | 20 +- ...O.java => EventReadOneByIdRequestDTO.java} | 4 +- ...ava => FriendshipCreateOneRequestDTO.java} | 10 +- ...FriendshipReadFriendDetailsRequestDTO.java | 31 ++ .../FriendshipReadStatusRequestDTO.java | 38 +++ ...va => FriendshipCreateOneResponseDTO.java} | 21 +- ...riendshipReadFriendDetailsResponseDTO.java | 54 ++++ .../FriendshipReadStatusResponseDTO.java | 47 +++ .../FriendshipRequestStatusResponseDTO.java | 57 ---- .../lions/dev/entity/friends/Friendship.java | 35 +-- .../FriendshipNotFoundException.java | 4 - .../dev/repository/FriendshipRepository.java | 53 +--- .../dev/resource/FriendshipResource.java | 268 +++++++++-------- .../lions/dev/service/FriendshipService.java | 273 +++++++++++------- .../com/lions/dev/service/UsersService.java | 31 +- src/main/resources/application.properties | 2 +- 16 files changed, 568 insertions(+), 380 deletions(-) rename src/main/java/com/lions/dev/dto/request/events/{EventGetOneByIdRequestDTO.java => EventReadOneByIdRequestDTO.java} (86%) rename src/main/java/com/lions/dev/dto/request/friends/{FriendshipRequestDTO.java => FriendshipCreateOneRequestDTO.java} (60%) create mode 100644 src/main/java/com/lions/dev/dto/request/friends/FriendshipReadFriendDetailsRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/request/friends/FriendshipReadStatusRequestDTO.java rename src/main/java/com/lions/dev/dto/response/friends/{FriendshipResponseDTO.java => FriendshipCreateOneResponseDTO.java} (50%) create mode 100644 src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/friends/FriendshipReadStatusResponseDTO.java delete mode 100644 src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java diff --git a/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java index 75bac61..e0ccaa1 100644 --- a/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java +++ b/src/main/java/com/lions/dev/core/errors/GlobalExceptionHandler.java @@ -5,17 +5,19 @@ import com.lions.dev.core.errors.exceptions.EventNotFoundException; import com.lions.dev.core.errors.exceptions.NotFoundException; import com.lions.dev.core.errors.exceptions.ServerException; import com.lions.dev.core.errors.exceptions.UnauthorizedException; - import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; +import org.jboss.logging.Logger; /** * Gestionnaire global des exceptions pour l'API. * Ce gestionnaire intercepte les exceptions spécifiques et renvoie des réponses appropriées. */ @Provider -public class GlobalExceptionHandler implements ExceptionMapper { +public class GlobalExceptionHandler implements ExceptionMapper { + + private static final Logger logger = Logger.getLogger(GlobalExceptionHandler.class); /** * Gère les exceptions non traitées et retourne une réponse appropriée. @@ -24,18 +26,26 @@ public class GlobalExceptionHandler implements ExceptionMapper { * @return Une réponse HTTP avec un message d'erreur et le code de statut approprié. */ @Override - public Response toResponse(Exception exception) { + public Response toResponse(Throwable exception) { if (exception instanceof BadRequestException) { + logger.warn("BadRequestException intercepted: " + exception.getMessage()); return buildResponse(Response.Status.BAD_REQUEST, exception.getMessage()); } else if (exception instanceof EventNotFoundException || exception instanceof NotFoundException) { + logger.warn("NotFoundException intercepted: " + exception.getMessage()); return buildResponse(Response.Status.NOT_FOUND, exception.getMessage()); } else if (exception instanceof UnauthorizedException) { + logger.warn("UnauthorizedException intercepted: " + exception.getMessage()); return buildResponse(Response.Status.UNAUTHORIZED, exception.getMessage()); } else if (exception instanceof ServerException) { + logger.error("ServerException intercepted: " + exception.getMessage()); return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur interne du serveur."); + } else if (exception instanceof RuntimeException) { + logger.error("RuntimeException intercepted: " + exception.getMessage()); + return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur inattendue."); + } else { + logger.error("Unexpected error: " + exception.getMessage(), exception); + return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur inattendue : " + exception.getMessage()); } - - return buildResponse(Response.Status.INTERNAL_SERVER_ERROR, "Erreur inattendue : " + exception.getMessage()); } /** diff --git a/src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventReadOneByIdRequestDTO.java similarity index 86% rename from src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java rename to src/main/java/com/lions/dev/dto/request/events/EventReadOneByIdRequestDTO.java index 3a07606..7765d9b 100644 --- a/src/main/java/com/lions/dev/dto/request/events/EventGetOneByIdRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/events/EventReadOneByIdRequestDTO.java @@ -9,12 +9,12 @@ import java.util.UUID; */ @lombok.Getter @lombok.Setter -public class EventGetOneByIdRequestDTO { +public class EventReadOneByIdRequestDTO { @NotNull(message = "L'ID de l'événement est obligatoire.") private UUID eventId; // ID de l'événement à lire - public EventGetOneByIdRequestDTO() { + public EventReadOneByIdRequestDTO() { System.out.println("[LOG] DTO de requête de lecture d'événement initialisé."); } } diff --git a/src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java b/src/main/java/com/lions/dev/dto/request/friends/FriendshipCreateOneRequestDTO.java similarity index 60% rename from src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java rename to src/main/java/com/lions/dev/dto/request/friends/FriendshipCreateOneRequestDTO.java index 9804d95..b439a6b 100644 --- a/src/main/java/com/lions/dev/dto/request/friends/FriendshipRequestDTO.java +++ b/src/main/java/com/lions/dev/dto/request/friends/FriendshipCreateOneRequestDTO.java @@ -13,12 +13,18 @@ import java.util.UUID; @Getter @Setter @NoArgsConstructor -public class FriendshipRequestDTO { +public class FriendshipCreateOneRequestDTO { private UUID userId; // ID de l'utilisateur qui envoie la demande private UUID friendId; // ID de l'utilisateur qui reçoit la demande - public FriendshipRequestDTO(UUID userId, UUID friendId) { + /** + * Constructeur avec paramètres pour initialiser les IDs. + * + * @param userId L'ID de l'utilisateur qui envoie la demande d'amitié. + * @param friendId L'ID de l'utilisateur qui reçoit la demande d'amitié. + */ + public FriendshipCreateOneRequestDTO(UUID userId, UUID friendId) { this.userId = userId; this.friendId = friendId; } diff --git a/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadFriendDetailsRequestDTO.java b/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadFriendDetailsRequestDTO.java new file mode 100644 index 0000000..9b69a5b --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadFriendDetailsRequestDTO.java @@ -0,0 +1,31 @@ +package com.lions.dev.dto.request.friends; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +/** + * DTO pour récupérer les détails d'un ami. + * Contient les informations nécessaires pour récupérer les détails d'un ami spécifique. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipReadFriendDetailsRequestDTO { + + private UUID userId; // ID de l'utilisateur demandant les détails + private UUID friendId; // ID de l'ami dont les détails sont requis + + /** + * Constructeur avec paramètres pour initialiser les IDs. + * + * @param userId L'ID de l'utilisateur demandant les détails de l'ami. + * @param friendId L'ID de l'ami dont les détails sont requis. + */ + public FriendshipReadFriendDetailsRequestDTO(UUID userId, UUID friendId) { + this.userId = userId; + this.friendId = friendId; + } +} diff --git a/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadStatusRequestDTO.java b/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadStatusRequestDTO.java new file mode 100644 index 0000000..8faf8d5 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/friends/FriendshipReadStatusRequestDTO.java @@ -0,0 +1,38 @@ +package com.lions.dev.dto.request.friends; + +import com.lions.dev.entity.friends.FriendshipStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.UUID; + +/** + * DTO de requête pour récupérer les demandes d'amitié par statut. + * Contient les informations nécessaires pour filtrer les demandes d'amitié d'un utilisateur. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipReadStatusRequestDTO { + + private UUID userId; // ID de l'utilisateur + private FriendshipStatus status; // Statut des demandes (PENDING, ACCEPTED, REJECTED) + private int page = 1; // Numéro de la page pour la pagination + private int size = 10; // Taille de la page pour la pagination + + /** + * Constructeur avec paramètres pour initialiser les informations de la demande. + * + * @param userId ID de l'utilisateur + * @param status Statut des demandes à récupérer + * @param page Numéro de la page pour la pagination + * @param size Nombre d'éléments par page + */ + public FriendshipReadStatusRequestDTO(UUID userId, FriendshipStatus status, int page, int size) { + this.userId = userId; + this.status = status; + this.page = page; + this.size = size; + } +} diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipCreateOneResponseDTO.java similarity index 50% rename from src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java rename to src/main/java/com/lions/dev/dto/response/friends/FriendshipCreateOneResponseDTO.java index cfdbeca..368d5d0 100644 --- a/src/main/java/com/lions/dev/dto/response/friends/FriendshipResponseDTO.java +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipCreateOneResponseDTO.java @@ -16,16 +16,21 @@ import java.util.UUID; @Getter @Setter @NoArgsConstructor -public class FriendshipResponseDTO { +public class FriendshipCreateOneResponseDTO { - private UUID id; - private UUID userId; - private UUID friendId; - private FriendshipStatus status; - private LocalDateTime createdAt; - private LocalDateTime updatedAt; + private UUID id; // ID de la relation d'amitié + private UUID userId; // ID de l'utilisateur qui a envoyé la demande + private UUID friendId; // ID de l'utilisateur qui a reçu la demande + private FriendshipStatus status; // Statut de la relation d'amitié (PENDING, ACCEPTED, REJECTED) + private LocalDateTime createdAt; // Date de création de la relation d'amitié + private LocalDateTime updatedAt; // Date de la dernière mise à jour - public FriendshipResponseDTO(Friendship friendship) { + /** + * Constructeur pour mapper l'entité `Friendship` à ce DTO. + * + * @param friendship L'entité `Friendship` à convertir en DTO. + */ + public FriendshipCreateOneResponseDTO(Friendship friendship) { this.id = friendship.getId(); this.userId = friendship.getUser().getId(); this.friendId = friendship.getFriend().getId(); 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 new file mode 100644 index 0000000..e0655fd --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadFriendDetailsResponseDTO.java @@ -0,0 +1,54 @@ +package com.lions.dev.dto.response.friends; + +import com.lions.dev.entity.friends.FriendshipStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO de réponse pour les détails d'un ami. + * Contient toutes les informations disponibles sur un ami spécifique. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipReadFriendDetailsResponseDTO { + + private UUID userId; // ID de l'utilisateur qui a initié la relation + private UUID friendId; // ID de l'ami + private String friendLastName; // Nom de l'ami + private String friendFirstName; // Prénom de l'ami + private String friendEmail; // Email de l'ami + 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 + + /** + * Constructeur pour initialiser le DTO avec des informations sur l'ami. + * + * @param userId L'ID de l'utilisateur initiant la demande d'amitié. + * @param friendId L'ID de l'ami. + * @param friendLastName Le nom de l'ami. + * @param friendFirstName Le prénom de l'ami. + * @param friendEmail L'email 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, + LocalDateTime createdAt, LocalDateTime updatedAt) { + this.userId = userId; + this.friendId = friendId; + this.friendLastName = friendLastName; + this.friendFirstName = friendFirstName; + this.friendEmail = friendEmail; + this.status = status; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } +} diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadStatusResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadStatusResponseDTO.java new file mode 100644 index 0000000..5f9fb63 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/friends/FriendshipReadStatusResponseDTO.java @@ -0,0 +1,47 @@ +package com.lions.dev.dto.response.friends; + +import com.lions.dev.entity.friends.Friendship; +import com.lions.dev.entity.friends.FriendshipStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO de réponse pour les demandes d'amitié filtrées par statut. + * Contient les informations essentielles sans données sensibles. + */ +@Getter +@Setter +@NoArgsConstructor +public class FriendshipReadStatusResponseDTO { + + private UUID friendshipId; // ID de la relation d'amitié + private UUID userId; // ID de l'utilisateur ayant initié la demande + private String userNom; // Nom de l'utilisateur ayant initié la demande + private String userPrenoms; // Prénoms de l'utilisateur ayant initié la demande + private UUID friendId; // ID de l'utilisateur ayant reçu la demande + private String friendNom; // Nom de l'utilisateur ayant reçu la demande + private String friendPrenoms; // Prénoms de l'utilisateur ayant reçu la demande + private FriendshipStatus status; // Statut de la demande d'amitié + private LocalDateTime createdAt; // Date de création de la demande + + /** + * Constructeur qui mappe directement l'entité `Friendship` à ce DTO. + * + * @param friendship L'entité `Friendship` à convertir en DTO. + */ + public FriendshipReadStatusResponseDTO(Friendship friendship) { + this.friendshipId = friendship.getId(); + this.userId = friendship.getUser().getId(); + this.userNom = friendship.getUser().getNom(); + this.userPrenoms = friendship.getUser().getPrenoms(); + this.friendId = friendship.getFriend().getId(); + this.friendNom = friendship.getFriend().getNom(); + this.friendPrenoms = friendship.getFriend().getPrenoms(); + this.status = friendship.getStatus(); + this.createdAt = friendship.getCreatedAt(); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java b/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java deleted file mode 100644 index fe94d57..0000000 --- a/src/main/java/com/lions/dev/dto/response/friends/FriendshipRequestStatusResponseDTO.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.lions.dev.dto.response.friends; - -import com.lions.dev.entity.friends.Friendship; -import com.lions.dev.entity.friends.FriendshipStatus; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.time.LocalDateTime; -import java.util.UUID; - -/** - * DTO de réponse pour les demandes d'amitié par statut. - * Contient les informations essentielles sans données sensibles. - */ -@Getter -@Setter -@NoArgsConstructor -public class FriendshipRequestStatusResponseDTO { - - private UUID friendshipId; - private UUID userId; - private String userNom; - private String userPrenoms; - private UUID friendId; - private String friendNom; - private String friendPrenoms; - private FriendshipStatus status; - private LocalDateTime createdAt; - - public FriendshipRequestStatusResponseDTO(UUID friendshipId, UUID userId, String userNom, String userPrenoms, - UUID friendId, String friendNom, String friendPrenoms, - FriendshipStatus status, LocalDateTime createdAt) { - this.friendshipId = friendshipId; - this.userId = userId; - this.userNom = userNom; - this.userPrenoms = userPrenoms; - this.friendId = friendId; - this.friendNom = friendNom; - this.friendPrenoms = friendPrenoms; - this.status = status; - this.createdAt = createdAt; - } - - // Constructor to map directly from Friendship entity - public FriendshipRequestStatusResponseDTO(Friendship friendship) { - this.friendshipId = friendship.getId(); - this.userId = friendship.getUser().getId(); - this.userNom = friendship.getUser().getNom(); - this.userPrenoms = friendship.getUser().getPrenoms(); - this.friendId = friendship.getFriend().getId(); - this.friendNom = friendship.getFriend().getNom(); - this.friendPrenoms = friendship.getFriend().getPrenoms(); - this.status = friendship.getStatus(); - this.createdAt = friendship.getCreatedAt(); - } -} diff --git a/src/main/java/com/lions/dev/entity/friends/Friendship.java b/src/main/java/com/lions/dev/entity/friends/Friendship.java index 4e0d126..475f4ae 100644 --- a/src/main/java/com/lions/dev/entity/friends/Friendship.java +++ b/src/main/java/com/lions/dev/entity/friends/Friendship.java @@ -1,29 +1,22 @@ package com.lions.dev.entity.friends; -import com.lions.dev.entity.BaseEntity; // Import de BaseEntity +import com.lions.dev.entity.BaseEntity; import com.lions.dev.entity.users.Users; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; +import lombok.*; -/** - * Représentation de l'entité Friendship qui gère les relations d'amitié entre utilisateurs. - */ +/** Représentation de l'entité Friendship qui gère les relations d'amitié entre utilisateurs. */ @Entity @Getter @Setter @NoArgsConstructor @AllArgsConstructor -@ToString @Builder +@ToString @Table(name = "friendships") -public class Friendship extends BaseEntity { // Hérite de BaseEntity +public class Friendship extends BaseEntity { - // L'utilisateur qui a initié la demande d'ami + // Utilisateur qui initie la demande @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private Users user; @@ -39,16 +32,18 @@ public class Friendship extends BaseEntity { // Hérite de BaseEntity private FriendshipStatus status; /** - * Log des changements de statut de l'amitié. + * Mise à jour du statut de la relation d'amitié avec log des changements. + * + * @param newStatus Nouveau statut de l'amitié */ public void setStatus(FriendshipStatus newStatus) { this.status = newStatus; System.out.println( - "[LOG] Changement de statut pour l'amitié entre " - + this.user.getEmail() - + " et " - + this.friend.getEmail() - + " - Nouveau statut : " - + this.status); + "[LOG] Statut changé pour l'amitié entre " + + this.user.getEmail() + + " et " + + this.friend.getEmail() + + " - Nouveau statut : " + + this.status); } } diff --git a/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java b/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java index 8f1a8ce..b84d376 100644 --- a/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java +++ b/src/main/java/com/lions/dev/exception/FriendshipNotFoundException.java @@ -8,8 +8,4 @@ public class FriendshipNotFoundException extends RuntimeException { public FriendshipNotFoundException(String message) { super(message); } - - public FriendshipNotFoundException(String message, Throwable cause) { - super(message, cause); - } } diff --git a/src/main/java/com/lions/dev/repository/FriendshipRepository.java b/src/main/java/com/lions/dev/repository/FriendshipRepository.java index a06ccb5..6394d8e 100644 --- a/src/main/java/com/lions/dev/repository/FriendshipRepository.java +++ b/src/main/java/com/lions/dev/repository/FriendshipRepository.java @@ -3,7 +3,7 @@ package com.lions.dev.repository; import com.lions.dev.entity.friends.Friendship; import com.lions.dev.entity.friends.FriendshipStatus; import com.lions.dev.entity.users.Users; -import io.quarkus.hibernate.orm.panache.PanacheRepository; +import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; import jakarta.enterprise.context.ApplicationScoped; import java.util.List; @@ -12,26 +12,29 @@ 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é. */ @ApplicationScoped -public class FriendshipRepository implements PanacheRepository { +public class FriendshipRepository implements PanacheRepositoryBase { /** - * Trouve une relation d'amitié entre deux utilisateurs. + * Trouver une relation d'amitié entre deux utilisateurs. * - * @param user L'utilisateur qui envoie la demande. + * @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. + * @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(); } /** - * Récupère la liste des amis d'un utilisateur. + * Récupérer la liste des amis d'un utilisateur, c'est-à-dire toutes les relations acceptées. * * @param user L'utilisateur dont on souhaite récupérer les amis. - * @return Une liste de relations d'amitié. + * @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é acceptées. */ public List findFriendsByUser(Users user, int page, int size) { return find("(user = ?1 or friend = ?1) and status = ?2", user, FriendshipStatus.ACCEPTED) @@ -40,37 +43,13 @@ public class FriendshipRepository implements PanacheRepository { } /** - * Trouve une relation d'amitié par son ID. + * Récupérer toutes les relations d'amitié d'un utilisateur avec un statut spécifique. * - * @param id L'ID de la relation d'amitié. - * @return Une Optional contenant la relation d'amitié, si elle existe. - */ - public Optional findById(UUID id) { - return find("id", id).firstResultOptional(); - } - - /** - * Supprime une relation d'amitié de la base de données. - * - * @param friendship La relation d'amitié à supprimer. - */ - public void deleteFriendship(Friendship friendship) { - if (friendship != null) { - this.delete(friendship); // Suppression de l'entité Friendship - System.out.println("[LOG] Entité Friendship supprimée : " + friendship.getId()); - } else { - System.out.println("[ERROR] Tentative de suppression d'une entité Friendship inexistante."); - } - } - - /** - * Récupère toutes les relations d'amitié d'un utilisateur ayant un statut particulier. - * - * @param user L'utilisateur dont on souhaite récupérer les amitiés. - * @param status Le statut des relations d'amitié à rechercher. - * @param page Le numéro de la page à récupérer. - * @param size Le nombre d'éléments par page. - * @return Une liste paginée de relations d'amitié ayant le statut spécifié pour cet utilisateur. + * @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. + * @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) diff --git a/src/main/java/com/lions/dev/resource/FriendshipResource.java b/src/main/java/com/lions/dev/resource/FriendshipResource.java index 6e18fe0..9ac70b3 100644 --- a/src/main/java/com/lions/dev/resource/FriendshipResource.java +++ b/src/main/java/com/lions/dev/resource/FriendshipResource.java @@ -1,12 +1,11 @@ package com.lions.dev.resource; -import com.lions.dev.dto.request.friends.FriendshipRequestDTO; -import com.lions.dev.dto.response.friends.FriendshipRequestStatusResponseDTO; -import com.lions.dev.dto.response.friends.FriendshipResponseDTO; -import com.lions.dev.entity.friends.Friendship; -import com.lions.dev.entity.friends.FriendshipStatus; -import com.lions.dev.entity.users.Users; -import com.lions.dev.repository.UsersRepository; +import com.lions.dev.dto.request.friends.FriendshipCreateOneRequestDTO; +import com.lions.dev.dto.request.friends.FriendshipReadFriendDetailsRequestDTO; +import com.lions.dev.dto.request.friends.FriendshipReadStatusRequestDTO; +import com.lions.dev.dto.response.friends.FriendshipCreateOneResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipReadFriendDetailsResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipReadStatusResponseDTO; import com.lions.dev.service.FriendshipService; import jakarta.inject.Inject; import jakarta.validation.Valid; @@ -17,7 +16,6 @@ import jakarta.ws.rs.core.Response; import java.util.List; import java.util.UUID; import org.eclipse.microprofile.openapi.annotations.Operation; -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.media.Content; import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; @@ -27,46 +25,45 @@ import org.jboss.logging.Logger; /** * Ressource REST pour gérer les amitiés. Ce contrôleur expose des endpoints pour envoyer, accepter, - * rejeter et supprimer des demandes d'amitié. Les opérations sont loguées pour suivre leur - * déroulement en temps réel. + * rejeter et supprimer des demandes d'amitié. Toutes les opérations sont loguées pour faciliter le + * suivi en temps réel. */ @Path("/friends") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) // Assure que la réponse sera en JSON +@Consumes(MediaType.APPLICATION_JSON) // Assure que la requête attend du JSON @Tag(name = "Friendship", description = "Opérations liées à la gestion des amis") public class FriendshipResource { - @Inject - FriendshipService friendshipService; - - @Inject - UsersRepository usersRepository; + @Inject FriendshipService friendshipService; // Injection du service d'amitié private static final Logger logger = Logger.getLogger(FriendshipResource.class); /** * Envoie une demande d'amitié. * - * @param request DTO contenant l'ID de l'utilisateur qui reçoit la demande. + * @param request DTO contenant l'ID de l'utilisateur qui envoie la demande et l'utilisateur qui + * la reçoit. * @return La relation d'amitié créée. */ @POST @Path("/send") @Operation( summary = "Envoyer une demande d'amitié", - description = "Envoie une demande d'amitié d'un utilisateur à un autre") + description = "Permet à un utilisateur d'envoyer une demande d'amitié") @APIResponses({ @APIResponse( responseCode = "200", - description = "Demande d'amitié envoyée", + description = "Demande d'amitié envoyée avec succès", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = FriendshipResponseDTO.class))), + schema = @Schema(implementation = FriendshipCreateOneResponseDTO.class))), @APIResponse(responseCode = "400", description = "Requête invalide"), - @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + @APIResponse( + responseCode = "500", + description = "Erreur serveur lors de l'envoi de la demande d'amitié") }) - public Response sendFriendRequest(@Valid @NotNull FriendshipRequestDTO request) { + public Response sendFriendRequest(@Valid @NotNull FriendshipCreateOneRequestDTO request) { logger.info( "[LOG] Reçu une demande pour envoyer une demande d'amitié de l'utilisateur " + request.getUserId() @@ -74,16 +71,17 @@ public class FriendshipResource { + request.getFriendId()); try { - Friendship friendship = - friendshipService.sendFriendRequest(request.getUserId(), request.getFriendId()); + // Appel du service pour envoyer la demande d'amitié + FriendshipCreateOneResponseDTO friendshipResponse = + friendshipService.sendFriendRequest(request); logger.info( - "[LOG] Demande d'amitié envoyée avec succès : " - + friendship.getUser().getEmail() - + " à " - + friendship.getFriend().getEmail()); - return Response.ok(new FriendshipResponseDTO(friendship)).build(); + "[LOG] Demande d'amitié envoyée avec succès entre les utilisateurs " + + friendshipResponse.getUserId() + + " et " + + friendshipResponse.getFriendId()); + return Response.ok(friendshipResponse).build(); } catch (Exception e) { - logger.error("[ERROR] Erreur lors de l'envoi de la demande d'amitié : " + e.getMessage()); + logger.error("[ERROR] Erreur lors de l'envoi de la demande d'amitié : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("{\"message\": \"Erreur lors de l'envoi de la demande d'amitié.\"}") .build(); @@ -108,30 +106,28 @@ public class FriendshipResource { content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = FriendshipResponseDTO.class))), + schema = @Schema(implementation = FriendshipCreateOneResponseDTO.class))), @APIResponse(responseCode = "404", description = "Demande d'amitié non trouvée"), - @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + @APIResponse( + responseCode = "500", + description = "Erreur lors de l'acceptation de la demande d'amitié") }) public Response acceptFriendRequest(@PathParam("friendshipId") UUID friendshipId) { logger.info( - "[LOG] Reçu une demande pour accepter une demande d'amitié avec l'ID : " + friendshipId); + "[LOG] Reçu une demande pour accepter la demande d'amitié avec l'ID : " + friendshipId); try { - Friendship friendship = friendshipService.acceptFriendRequest(friendshipId); + FriendshipCreateOneResponseDTO friendshipResponse = + friendshipService.acceptFriendRequest(friendshipId); logger.info( - "[LOG] Demande d'amitié acceptée entre " - + friendship.getUser().getEmail() + "[LOG] Demande d'amitié acceptée avec succès entre les utilisateurs " + + friendshipResponse.getUserId() + " et " - + friendship.getFriend().getEmail()); - return Response.ok(new FriendshipResponseDTO(friendship)).build(); - } catch (NotFoundException e) { - logger.error("[ERROR] Demande d'amitié non trouvée : " + e.getMessage()); - return Response.status(Response.Status.NOT_FOUND) - .entity("{\"message\": \"Demande d'amitié non trouvée.\"}") - .build(); + + friendshipResponse.getFriendId()); + return Response.ok(friendshipResponse).build(); } catch (Exception e) { logger.error( - "[ERROR] Erreur lors de l'acceptation de la demande d'amitié : " + e.getMessage()); + "[ERROR] Erreur lors de l'acceptation de la demande d'amitié : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("{\"message\": \"Erreur lors de l'acceptation de la demande d'amitié.\"}") .build(); @@ -152,23 +148,18 @@ public class FriendshipResource { @APIResponses({ @APIResponse(responseCode = "204", description = "Demande d'amitié rejetée"), @APIResponse(responseCode = "404", description = "Demande d'amitié non trouvée"), - @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + @APIResponse(responseCode = "500", description = "Erreur lors du rejet de la demande d'amitié") }) public Response rejectFriendRequest(@PathParam("friendshipId") UUID friendshipId) { logger.info( - "[LOG] Reçu une demande pour rejeter une demande d'amitié avec l'ID : " + friendshipId); + "[LOG] Reçu une demande pour rejeter la demande d'amitié avec l'ID : " + friendshipId); try { friendshipService.rejectFriendRequest(friendshipId); - logger.info("[LOG] Demande d'amitié rejetée pour l'ID : " + friendshipId); + logger.info("[LOG] Demande d'amitié rejetée avec succès."); return Response.noContent().build(); - } catch (NotFoundException e) { - logger.error("[ERROR] Demande d'amitié non trouvée : " + e.getMessage()); - return Response.status(Response.Status.NOT_FOUND) - .entity("{\"message\": \"Demande d'amitié non trouvée.\"}") - .build(); } catch (Exception e) { - logger.error("[ERROR] Erreur lors du rejet de la demande d'amitié : " + e.getMessage()); + logger.error("[ERROR] Erreur lors du rejet de la demande d'amitié : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("{\"message\": \"Erreur lors du rejet de la demande d'amitié.\"}") .build(); @@ -189,7 +180,9 @@ public class FriendshipResource { @APIResponses({ @APIResponse(responseCode = "204", description = "Relation d'amitié supprimée"), @APIResponse(responseCode = "404", description = "Relation d'amitié non trouvée"), - @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + @APIResponse( + responseCode = "500", + description = "Erreur lors de la suppression de la relation d'amitié") }) public Response removeFriend(@PathParam("friendshipId") UUID friendshipId) { logger.info( @@ -197,16 +190,11 @@ public class FriendshipResource { try { friendshipService.removeFriend(friendshipId); - logger.info("[LOG] Relation d'amitié supprimée avec succès pour l'ID : " + friendshipId); + logger.info("[LOG] Relation d'amitié supprimée avec succès."); return Response.noContent().build(); - } catch (NotFoundException e) { - logger.error("[ERROR] Relation d'amitié non trouvée : " + e.getMessage()); - return Response.status(Response.Status.NOT_FOUND) - .entity("{\"message\": \"Relation d'amitié non trouvée.\"}") - .build(); } catch (Exception e) { logger.error( - "[ERROR] Erreur lors de la suppression de la relation d'amitié : " + e.getMessage()); + "[ERROR] Erreur lors de la suppression de la relation d'amitié : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("{\"message\": \"Erreur lors de la suppression de la relation d'amitié.\"}") .build(); @@ -216,102 +204,140 @@ public class FriendshipResource { /** * Récupère la liste des amis d'un utilisateur. * - * @param userId L'ID de l'utilisateur dont on veut récupérer les amis. - * @param page Numéro de la page pour la pagination. - * @param size Nombre d'éléments par page. - * @return La liste des amis de l'utilisateur. + * @param userId L'ID de l'utilisateur + * @param page Numéro de la page pour la pagination + * @param size Nombre d'éléments par page + * @return Liste des amis de l'utilisateur avec pagination */ @GET @Path("/list/{userId}") @Operation( - summary = "Lister les amis d'un utilisateur", - description = "Récupère la liste de tous les amis d'un utilisateur donné") + summary = "Récupérer la liste des amis", + description = "Retourne la liste des amis d'un utilisateur avec pagination") @APIResponses({ @APIResponse( responseCode = "200", - description = "Liste des amis récupérée", + description = "Liste des amis récupérée avec succès", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = - @Schema( - type = SchemaType.ARRAY, - implementation = FriendshipResponseDTO.class))), + schema = @Schema(implementation = FriendshipReadFriendDetailsResponseDTO.class))), @APIResponse(responseCode = "404", description = "Utilisateur non trouvé"), - @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + @APIResponse(responseCode = "500", description = "Erreur lors de la récupération des amis") }) public Response listFriends( @PathParam("userId") UUID userId, - @QueryParam("page") @DefaultValue("1") int page, + @QueryParam("page") @DefaultValue("0") int page, @QueryParam("size") @DefaultValue("10") int size) { logger.info( "[LOG] Reçu une demande pour récupérer la liste des amis de l'utilisateur avec l'ID : " + userId); try { - List friends = friendshipService.listFriends(userId, page, size); - logger.info( - "[LOG] Liste des amis récupérée avec succès pour l'utilisateur " - + userId - + ", nombre d'amis : " - + friends.size()); - return Response.ok(friends.stream().map(FriendshipResponseDTO::new)).build(); - } catch (NotFoundException e) { - logger.error("[ERROR] Utilisateur non trouvé : " + e.getMessage()); - return Response.status(Response.Status.NOT_FOUND) - .entity("{\"message\": \"Utilisateur non trouvé.\"}") - .build(); + List friendships = + friendshipService.listFriends(userId, page, size); + logger.info("[LOG] Liste des amis récupérée avec succès."); + return Response.ok(friendships).build(); } catch (Exception e) { logger.error( - "[ERROR] Erreur lors de la récupération de la liste des amis : " + e.getMessage()); + "[ERROR] Erreur lors de la récupération de la liste des amis : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("{\"message\": \"Erreur lors de la récupération de la liste des amis.\"}") + .entity("{\"message\": \"Erreur lors de la récupération des amis.\"}") .build(); } } /** - * Endpoint pour récupérer les demandes d'amitié avec un statut spécifique. + * Récupérer les demandes d'amitié avec un statut spécifique. * - * @param userId L'ID de l'utilisateur. - * @param status Le statut des demandes à filtrer (PENDING, ACCEPTED, REJECTED). - * @param page Le numéro de la page à récupérer. - * @param size Le nombre d'éléments par page. - * @return La liste paginée des demandes d'amitié avec le statut spécifié. + * @param request DTO contenant les informations de filtrage (statut). + * @return Liste des demandes d'amitié avec le statut spécifié. */ - @GET + @POST @Path("/status") @Operation( - summary = "Récupérer les demandes d'amitié faites par un utilisateur par statut", - description = "Retourne la liste des demandes d'amitié faites par un utilisateur avec un " - + "statut particulier.") + summary = "Récupérer les demandes d'amitié par statut", + description = "Retourne la liste des demandes d'amitié avec un statut particulier") + @APIResponses({ + @APIResponse( + responseCode = "200", + description = "Demandes d'amitié récupérées", + content = + @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FriendshipReadStatusResponseDTO.class))), + @APIResponse(responseCode = "404", description = "Utilisateur non trouvé"), + @APIResponse( + responseCode = "500", + description = "Erreur lors de la récupération des demandes d'amitié") + }) public Response listFriendRequestsByStatus( - @QueryParam("userId") UUID userId, - @QueryParam("status") FriendshipStatus status, - @QueryParam("page") @DefaultValue("1") int page, - @QueryParam("size") @DefaultValue("10") int size) { + @Valid @NotNull FriendshipReadStatusRequestDTO request) { + logger.info("[LOG] Récupération des demandes d'amitié avec le statut : " + request.getStatus()); - logger.info("[LOG] Récupération des demandes d'amitié avec le statut : " + status); + try { + List friendships = + friendshipService.listFriendRequestsByStatus(request); + logger.info("[LOG] " + friendships.size() + " demandes d'amitié récupérées avec succès."); + return Response.ok(friendships).build(); + } catch (Exception e) { + logger.error( + "[ERROR] Erreur lors de la récupération des demandes d'amitié : " + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de la récupération des demandes d'amitié.\"}") + .build(); + } + } - // Récupère l'utilisateur à partir de l'ID fourni - Users user = usersRepository.findById(userId); - if (user == null) { + /** + * Récupère les détails complets d'un ami. + * + * @param request DTO contenant l'ID de l'utilisateur et de l'ami dont les détails sont requis. + * @return Les détails complets de l'ami. + */ + @POST + @Path("/details") + @Operation( + summary = "Récupérer les détails d'un ami", + description = "Permet de récupérer toutes les informations disponibles sur un ami spécifique") + @APIResponses({ + @APIResponse( + responseCode = "200", + description = "Détails de l'ami récupérés avec succès", + content = + @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FriendshipReadFriendDetailsResponseDTO.class))), + @APIResponse(responseCode = "404", description = "Ami non trouvé"), + @APIResponse(responseCode = "500", description = "Erreur serveur lors de la récupération des détails de l'ami") + }) + public Response getFriendDetails(@Valid @NotNull FriendshipReadFriendDetailsRequestDTO request) { + logger.info( + "[LOG] Reçu une demande pour récupérer les détails de l'ami avec l'ID : " + + request.getFriendId() + " pour l'utilisateur : " + request.getUserId()); + + try { + // Appel du service pour récupérer les détails de l'ami + FriendshipReadFriendDetailsResponseDTO friendDetails = + friendshipService.getFriendDetails(request); + logger.info( + "[LOG] Détails de l'ami récupérés avec succès pour l'utilisateur : " + + request.getUserId() + ", ami ID : " + request.getFriendId()); + return Response.ok(friendDetails).build(); + } catch (NotFoundException e) { + logger.warn( + "[WARN] Aucun ami trouvé pour l'utilisateur : " + request.getUserId() + + " avec l'ID de l'ami : " + request.getFriendId()); return Response.status(Response.Status.NOT_FOUND) - .entity("{\"message\": \"Utilisateur non trouvé.\"}") + .entity("{\"message\": \"Ami non trouvé.\"}") + .build(); + } catch (Exception e) { + logger.error( + "[ERROR] Erreur lors de la récupération des détails de l'ami : " + + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("{\"message\": \"Erreur lors de la récupération des détails de l'ami.\"}") .build(); } - - // Ajuste la pagination (Panache commence à 0) - int adjustedPage = page - 1; - if (adjustedPage < 0) adjustedPage = 0; - - List friendships = friendshipService.listFriendRequestsByStatus(user, status, adjustedPage, size); - - // Transformation des entités Friendship en DTOs adaptés - List responseDTOs = friendships.stream() - .map(FriendshipRequestStatusResponseDTO::new) - .toList(); - - return Response.ok(responseDTOs).build(); } } diff --git a/src/main/java/com/lions/dev/service/FriendshipService.java b/src/main/java/com/lions/dev/service/FriendshipService.java index d8b11ae..237bc2d 100644 --- a/src/main/java/com/lions/dev/service/FriendshipService.java +++ b/src/main/java/com/lions/dev/service/FriendshipService.java @@ -1,5 +1,11 @@ package com.lions.dev.service; +import com.lions.dev.dto.request.friends.FriendshipCreateOneRequestDTO; +import com.lions.dev.dto.request.friends.FriendshipReadFriendDetailsRequestDTO; +import com.lions.dev.dto.request.friends.FriendshipReadStatusRequestDTO; +import com.lions.dev.dto.response.friends.FriendshipCreateOneResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipReadFriendDetailsResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipReadStatusResponseDTO; import com.lions.dev.entity.friends.Friendship; import com.lions.dev.entity.friends.FriendshipStatus; import com.lions.dev.entity.users.Users; @@ -10,175 +16,224 @@ import com.lions.dev.repository.UsersRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; +import org.jboss.logging.Logger; + import java.util.List; -import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; /** - * Service de gestion des amitiés. Ce service gère l'envoi, l'acceptation, le rejet et la - * suppression d'amitiés. + * Service pour gérer les relations d'amitié. + * Contient la logique métier pour envoyer, accepter, rejeter, et supprimer des relations d'amitié. */ @ApplicationScoped public class FriendshipService { - @Inject FriendshipRepository friendshipRepository; + @Inject + FriendshipRepository friendshipRepository; // Injecte le repository des amitiés + @Inject + UsersRepository usersRepository; // Injecte le repository des utilisateurs - @Inject UsersRepository usersRepository; + private static final Logger logger = Logger.getLogger(FriendshipService.class); /** * Envoie une demande d'amitié entre deux utilisateurs. * - * @param userId L'ID de l'utilisateur qui envoie la demande. - * @param friendId L'ID de l'utilisateur qui reçoit la demande. - * @return La relation d'amitié créée. - * @throws UserNotFoundException Si l'un des utilisateurs n'est pas trouvé. + * @param request DTO contenant les informations sur l'utilisateur et l'ami. + * @return Le DTO de la relation d'amitié créée. */ @Transactional - public Friendship sendFriendRequest(UUID userId, UUID friendId) { - System.out.println( - "[LOG] Envoi de demande d'amitié de l'utilisateur " - + userId - + " à l'utilisateur " - + friendId); + public FriendshipCreateOneResponseDTO sendFriendRequest(FriendshipCreateOneRequestDTO request) { + logger.info("[LOG] Envoi d'une demande d'amitié de l'utilisateur " + request.getUserId() + " à l'utilisateur " + request.getFriendId()); - Users user = usersRepository.findById(userId); - Users friend = usersRepository.findById(friendId); + // Récupérer les utilisateurs concernés + Users user = usersRepository.findById(request.getUserId()); + Users friend = usersRepository.findById(request.getFriendId()); if (user == null || friend == null) { - System.out.println( - "[ERROR] Utilisateur non trouvé pour l'ID : " + (user == null ? userId : friendId)); - throw new UserNotFoundException("L'utilisateur avec l'ID spécifié n'existe pas."); + String notFoundId = user == null ? request.getUserId().toString() : request.getFriendId().toString(); + logger.error("[ERROR] Utilisateur non trouvé pour l'ID : " + notFoundId); + throw new UserNotFoundException("Utilisateur avec l'ID " + notFoundId + " introuvable."); } - Optional existingFriendship = friendshipRepository.findByUsers(user, friend); - if (existingFriendship.isPresent()) { - System.out.println("[ERROR] Une relation d'amitié existe déjà entre ces deux utilisateurs."); + // Vérifier s'il existe déjà une relation d'amitié + Friendship existingFriendship = friendshipRepository.findByUsers(user, friend).orElse(null); + if (existingFriendship != null) { + logger.error("[ERROR] Relation d'amitié déjà existante entre les utilisateurs."); throw new IllegalArgumentException("Relation d'amitié déjà existante."); } - Friendship friendship = - Friendship.builder().user(user).friend(friend).status(FriendshipStatus.PENDING).build(); - + // Créer et persister une nouvelle relation d'amitié + Friendship friendship = new Friendship(user, friend, FriendshipStatus.PENDING); friendshipRepository.persist(friendship); - System.out.println( - "[LOG] Demande d'amitié envoyée de " + user.getEmail() + " à " + friend.getEmail()); - return friendship; + logger.info("[LOG] Demande d'amitié envoyée avec succès."); + return new FriendshipCreateOneResponseDTO(friendship); } /** - * Accepte une demande d'amitié. + * Accepter une demande d'amitié. * - * @param friendshipId L'ID de la demande d'amitié. - * @return La relation d'amitié acceptée. - * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + * @param friendshipId ID de la demande à accepter. + * @return Le DTO de la relation d'amitié acceptée. */ @Transactional - public Friendship acceptFriendRequest(UUID friendshipId) { - System.out.println("[LOG] Acceptation de la demande d'amitié avec l'ID : " + friendshipId); - - Friendship friendship = - friendshipRepository - .findById(friendshipId) - .orElseThrow(() -> new FriendshipNotFoundException("Demande d'amitié introuvable.")); - - if (friendship.getStatus() == FriendshipStatus.ACCEPTED) { - System.out.println("[ERROR] La demande d'amitié a déjà été acceptée."); - throw new IllegalArgumentException("Cette demande d'amitié a déjà été acceptée."); + public FriendshipCreateOneResponseDTO acceptFriendRequest(UUID friendshipId) { + Friendship friendship = friendshipRepository.findById(friendshipId); + if (friendship == null) { + 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."); + throw new IllegalArgumentException("Demande d'amitié déjà acceptée."); + } + + // Accepter la demande friendship.setStatus(FriendshipStatus.ACCEPTED); friendshipRepository.persist(friendship); - System.out.println( - "[LOG] Demande d'amitié acceptée entre " - + friendship.getUser().getEmail() - + " et " - + friendship.getFriend().getEmail()); - return friendship; + logger.info("[LOG] Demande d'amitié acceptée avec succès."); + return new FriendshipCreateOneResponseDTO(friendship); } /** - * Rejette une demande d'amitié. + * Rejeter une demande d'amitié. * - * @param friendshipId L'ID de la demande d'amitié. - * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + * @param friendshipId ID de la demande à rejeter. */ @Transactional public void rejectFriendRequest(UUID friendshipId) { - System.out.println("[LOG] Rejet de la demande d'amitié avec l'ID : " + friendshipId); - - Friendship friendship = - friendshipRepository - .findById(friendshipId) - .orElseThrow(() -> new FriendshipNotFoundException("Demande d'amitié introuvable.")); + Friendship friendship = friendshipRepository.findById(friendshipId); + if (friendship == null) { + throw new FriendshipNotFoundException("Demande d'amitié introuvable."); + } friendship.setStatus(FriendshipStatus.REJECTED); friendshipRepository.persist(friendship); - System.out.println( - "[LOG] Demande d'amitié rejetée entre " - + friendship.getUser().getEmail() - + " et " - + friendship.getFriend().getEmail()); + + logger.info("[LOG] Demande d'amitié rejetée."); } /** - * Supprime une relation d'amitié. + * Supprimer une relation d'amitié. * - * @param friendshipId L'ID de la relation d'amitié à supprimer. - * @throws FriendshipNotFoundException Si la relation d'amitié n'est pas trouvée. + * @param friendshipId ID de la relation à supprimer. */ @Transactional public void removeFriend(UUID friendshipId) { - System.out.println("[LOG] Suppression de la relation d'amitié avec l'ID : " + friendshipId); - - Friendship friendship = - friendshipRepository - .findById(friendshipId) - .orElseThrow(() -> new FriendshipNotFoundException("Amitié introuvable.")); - - friendshipRepository.deleteFriendship(friendship); // Appel à deleteFriendship - System.out.println( - "[LOG] Amitié supprimée entre " - + friendship.getUser().getEmail() - + " et " - + friendship.getFriend().getEmail()); - } - - /** - * Récupère la liste des amis d'un utilisateur avec pagination. - * - * @param userId L'ID de l'utilisateur. - * @param page Le numéro de la page à récupérer. - * @param size Le nombre d'éléments par page. - * @return La liste paginée des relations d'amitié. - * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. - */ - public List listFriends(UUID userId, int page, int size) { - System.out.println( - "[LOG] Récupération de la liste paginée des amis pour l'utilisateur avec l'ID : " + userId); - - Users user = usersRepository.findById(userId); - if (user == null) { - System.out.println("[ERROR] Utilisateur non trouvé pour l'ID : " + userId); - throw new UserNotFoundException("Utilisateur non trouvé."); + Friendship friendship = friendshipRepository.findById(friendshipId); + if (friendship == null) { + throw new FriendshipNotFoundException("Relation d'amitié introuvable."); } - return friendshipRepository.findFriendsByUser(user, page, size); + friendshipRepository.delete(friendship); + logger.info("[LOG] Relation d'amitié supprimée."); } /** - * Récupère toutes les demandes d'amitié avec un statut spécifique. + * Récupère les détails d'un ami spécifique pour un utilisateur donné. * - * @param user L'utilisateur. - * @param status Le statut des demandes d'amitié à récupérer (PENDING, ACCEPTED, REJECTED). - * @param page Le numéro de la page à récupérer. - * @param size Le nombre d'éléments par page. - * @return La liste paginée des relations d'amitié avec le statut spécifié. + * @param request DTO contenant l'ID de l'utilisateur et de l'ami. + * @return Le DTO des détails de l'ami. */ - public List listFriendRequestsByStatus(Users user, FriendshipStatus status, int page, int size) { - System.out.println("[LOG] Récupération des demandes d'amitié avec le statut : " + status); - return friendshipRepository.findByUserAndStatus(user, status, page, size); + @Transactional + public FriendshipReadFriendDetailsResponseDTO getFriendDetails( + FriendshipReadFriendDetailsRequestDTO request) { + logger.info("[LOG] Tentative de récupération des détails de l'ami avec l'ID : " + + request.getFriendId() + " pour l'utilisateur : " + request.getUserId()); + + // Récupération de l'utilisateur et de l'ami + Users user = usersRepository.findById(request.getUserId()); + Users friend = usersRepository.findById(request.getFriendId()); + + if (user == null) { + logger.error("[ERROR] Utilisateur introuvable avec l'ID : " + request.getUserId()); + throw new UserNotFoundException("Utilisateur introuvable avec l'ID " + request.getUserId()); + } + + if (friend == null) { + logger.error("[ERROR] Ami introuvable avec l'ID : " + request.getFriendId()); + throw new UserNotFoundException("Ami introuvable avec l'ID " + request.getFriendId()); + } + + // Récupérer la relation d'amitié entre les deux utilisateurs + Friendship friendship = friendshipRepository.findByUsers(user, friend).orElse(null); + if (friendship == null) { + logger.error("[ERROR] Aucune relation d'amitié trouvée entre l'utilisateur et l'ami."); + throw new FriendshipNotFoundException("Relation d'amitié introuvable."); + } + + logger.info("[LOG] Détails de l'ami récupérés avec succès pour l'utilisateur : " + + user.getId() + ", ami ID : " + friend.getId()); + + // Création du DTO de réponse à partir des informations de l'ami et de la relation + return new FriendshipReadFriendDetailsResponseDTO( + user.getId(), // ID de l'utilisateur + friend.getId(), // ID de l'ami + friend.getNom(), // Nom de l'ami + friend.getPrenoms(), + friend.getEmail(), // Email 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 + ); } + /** + * Récupérer la liste des amis d'un utilisateur. + * + * @param userId ID de l'utilisateur. + * @param page Numéro de la page. + * @param size Taille de la page. + * @return Liste paginée des relations d'amitié. + */ + public List listFriends(UUID userId, int page, int size) { + Users user = usersRepository.findById(userId); + if (user == null) { + logger.error("[ERROR] Utilisateur non trouvé."); + throw new UserNotFoundException("Utilisateur introuvable."); + } + + // Récupérer les amitiés acceptées + List friendships = friendshipRepository.findFriendsByUser(user, page, size); + logger.info("[LOG] " + friendships.size() + " amis récupérés."); + + // Ajouter un log pour chaque amitié récupérée + friendships.forEach(friendship -> logger.info("[LOG] Ami : " + friendship.getFriend().getEmail())); + + return friendships.stream() + .map(friendship -> new FriendshipReadFriendDetailsResponseDTO( + friendship.getUser().getId(), + friendship.getFriend().getId(), + friendship.getFriend().getNom(), + friendship.getFriend().getPrenoms(), + friendship.getFriend().getEmail(), + friendship.getStatus(), + friendship.getCreatedAt(), + friendship.getUpdatedAt() + )) + .collect(Collectors.toList()); + } + + /** + * Récupérer les demandes d'amitié avec un statut spécifique. + * + * @param request DTO contenant les informations de filtrage (statut). + * @return Liste des demandes d'amitié avec le statut spécifié. + */ + public List listFriendRequestsByStatus(FriendshipReadStatusRequestDTO request) { + Users user = usersRepository.findById(request.getUserId()); + if (user == null) { + logger.error("[ERROR] Utilisateur non trouvé."); + throw new UserNotFoundException("Utilisateur introuvable."); + } + + // Récupérer les demandes d'amitié selon le statut + List friendships = friendshipRepository.findByUserAndStatus(user, request.getStatus(), request.getPage() - 1, request.getSize()); + logger.info("[LOG] " + friendships.size() + " demandes d'amitié récupérées."); + + return friendships.stream().map(FriendshipReadStatusResponseDTO::new).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/lions/dev/service/UsersService.java b/src/main/java/com/lions/dev/service/UsersService.java index 21678be..9480448 100644 --- a/src/main/java/com/lions/dev/service/UsersService.java +++ b/src/main/java/com/lions/dev/service/UsersService.java @@ -29,26 +29,29 @@ public class UsersService { * @return L'utilisateur créé. */ public Users createUser(UserCreateRequestDTO userCreateRequestDTO) { + // Vérification si l'email existe déjà + Optional existingUser = usersRepository.findByEmail(userCreateRequestDTO.getEmail()); + if (existingUser.isPresent()) { + throw new IllegalArgumentException("Un utilisateur avec cet email existe déjà."); + } + Users user = new Users(); user.setNom(userCreateRequestDTO.getNom()); user.setPrenoms(userCreateRequestDTO.getPrenoms()); user.setEmail(userCreateRequestDTO.getEmail()); user.setMotDePasse(userCreateRequestDTO.getMotDePasse()); // Hachage automatique - // Vérifier si le profile image est défini, sinon attribuer une image par défaut - if (userCreateRequestDTO.getProfileImageUrl() == null - || userCreateRequestDTO.getProfileImageUrl().isEmpty()) { - user.setProfileImageUrl("https://via.placeholder.com/150"); // Assigner une image par défaut - } else { - user.setProfileImageUrl(userCreateRequestDTO.getProfileImageUrl()); - } - - // Vérifier si le rôle est défini, sinon attribuer un rôle par défaut - if (userCreateRequestDTO.getRole() == null || userCreateRequestDTO.getRole().isEmpty()) { - user.setRole("USER"); // Assigner un rôle par défaut - } else { - user.setRole(userCreateRequestDTO.getRole()); - } + // Logique pour l'image et le rôle par défaut. + user.setProfileImageUrl( + userCreateRequestDTO.getProfileImageUrl() != null + ? userCreateRequestDTO.getProfileImageUrl() + : "https://via.placeholder.com/150" + ); + user.setRole( + userCreateRequestDTO.getRole() != null + ? userCreateRequestDTO.getRole() + : "USER" + ); usersRepository.persist(user); System.out.println("[LOG] Utilisateur créé : " + user.getEmail()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5cb4d5e..6fc7375 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -12,7 +12,7 @@ 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=drop-and-create +quarkus.hibernate-orm.database.generation=update quarkus.hibernate-orm.log.sql=true quarkus.datasource.devservices.enabled=false From 588984aa9c2f5fd9cbdc42f95dd2c03e54b37b9b Mon Sep 17 00:00:00 2001 From: DahoudG Date: Fri, 8 Nov 2024 20:30:39 +0000 Subject: [PATCH 7/8] Bon checkpoint + Refactoring --- .../events/EventReadManyByIdRequestDTO.java | 22 + .../response/comments/CommentResponseDTO.java | 71 ++ .../events/EventReadManyByIdResponseDTO.java | 42 + .../dto/response/users/UserResponseDTO.java | 69 ++ .../com/lions/dev/entity/comment/Comment.java | 44 +- .../com/lions/dev/entity/events/Events.java | 15 + .../com/lions/dev/entity/users/Users.java | 51 + .../dev/repository/FriendshipRepository.java | 11 +- .../lions/dev/resource/EventsResource.java | 927 ++++++++++-------- .../dev/resource/FriendshipResource.java | 43 +- .../com/lions/dev/service/EventService.java | 140 ++- .../com/lions/dev/service/FileService.java | 49 +- .../lions/dev/service/FriendshipService.java | 42 +- 13 files changed, 1048 insertions(+), 478 deletions(-) create mode 100644 src/main/java/com/lions/dev/dto/request/events/EventReadManyByIdRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/comments/CommentResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java diff --git a/src/main/java/com/lions/dev/dto/request/events/EventReadManyByIdRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventReadManyByIdRequestDTO.java new file mode 100644 index 0000000..a77220d --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/events/EventReadManyByIdRequestDTO.java @@ -0,0 +1,22 @@ +package com.lions.dev.dto.request.events; + +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * DTO de requête pour obtenir les événements créés par un utilisateur spécifique. + * Permet l'ajout futur de critères de filtre si nécessaire. + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class EventReadManyByIdRequestDTO { + + private UUID userId; // Identifiant de l'utilisateur pour lequel on souhaite obtenir les événements + + // Ajoutez ici d'autres critères de filtre si besoin, comme une plage de dates, un statut, etc. +} diff --git a/src/main/java/com/lions/dev/dto/response/comments/CommentResponseDTO.java b/src/main/java/com/lions/dev/dto/response/comments/CommentResponseDTO.java new file mode 100644 index 0000000..3ef04d5 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/comments/CommentResponseDTO.java @@ -0,0 +1,71 @@ +package com.lions.dev.dto.response.comments; + +import com.lions.dev.entity.comment.Comment; // Import de l'entité Comment +import lombok.Getter; +import lombok.Setter; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import java.util.UUID; + +/** + * DTO (Data Transfer Object) pour le commentaire. + *

+ * Cette classe est utilisée pour représenter un commentaire d'un événement dans les réponses de l'API. + * Elle permet de transférer les informations du commentaire sans exposer des données sensibles ou non nécessaires. + *

+ */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class CommentResponseDTO { + + /** + * Identifiant unique du commentaire. + * C'est un UUID généré de manière unique pour chaque commentaire. + */ + private UUID id; + + /** + * Texte du commentaire. + * Contient le contenu écrit par l'utilisateur pour un événement donné. + */ + private String texte; + + /** + * Identifiant de l'utilisateur qui a écrit le commentaire. + * Il permet d'identifier l'auteur du commentaire sans exposer d'autres informations sensibles. + */ + private UUID userId; + + /** + * Nom de l'utilisateur ayant écrit le commentaire. + * Le nom est inclus pour permettre une identification facile de l'auteur du commentaire. + */ + private String userNom; + + /** + * Prénom de l'utilisateur ayant écrit le commentaire. + * Prénom associé à l'auteur du commentaire. + */ + private String userPrenoms; + + /** + * Constructeur de DTO à partir d'une entité Comment. + *

+ * Ce constructeur permet de convertir l'entité {@link Comment} en un DTO simple qui peut être retourné dans les réponses API. + *

+ * + * @param comment L'entité {@link Comment} dont les informations sont extraites pour le DTO. + */ + public CommentResponseDTO(Comment comment) { + if (comment != null) { + this.id = comment.getId(); // Identifiant unique du commentaire + this.texte = comment.getText(); // Texte du commentaire + this.userId = comment.getUser().getId(); // Identifiant de l'utilisateur (auteur du commentaire) + this.userNom = comment.getUser().getNom(); // Nom de l'utilisateur + this.userPrenoms = comment.getUser().getPrenoms(); // Prénom de l'utilisateur + } + } +} 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 new file mode 100644 index 0000000..28795b5 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/events/EventReadManyByIdResponseDTO.java @@ -0,0 +1,42 @@ +package com.lions.dev.dto.response.events; + +import com.lions.dev.entity.events.Events; +import java.time.LocalDateTime; +import lombok.Getter; + +/** + * DTO pour renvoyer les informations des événements créés par un utilisateur spécifique. + * Ce DTO est utilisé pour structurer les données retournées dans la réponse. + */ +@Getter +public class EventReadManyByIdResponseDTO { + + private String id; // Identifiant de l'événement + private String title; // Titre de l'événement + private String description; // Description de l'événement + private LocalDateTime startDate; // Date de début de l'événement + private LocalDateTime endDate; // Date de fin de l'événement + private String location; // Lieu de l'événement + private String category; // Catégorie de l'événement + 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 + + /** + * Constructeur qui transforme une entité Events en DTO de réponse. + * + * @param event L'événement à convertir en DTO. + */ + public EventReadManyByIdResponseDTO(Events event) { + this.id = event.getId().toString(); + this.title = event.getTitle(); + this.description = event.getDescription(); + this.startDate = event.getStartDate(); + this.endDate = event.getEndDate(); + this.location = event.getLocation(); + this.category = event.getCategory(); + this.link = event.getLink(); + this.imageUrl = event.getImageUrl(); + this.status = event.getStatus(); + } +} diff --git a/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java b/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java new file mode 100644 index 0000000..0921ca9 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java @@ -0,0 +1,69 @@ +package com.lions.dev.dto; + +import com.lions.dev.entity.users.Users; // Import de l'entité Users +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * DTO (Data Transfer Object) pour l'utilisateur. + *

+ * Cette classe sert de représentation simplifiée d'un utilisateur, avec un ensemble d'informations nécessaires à + * la réponse de l'API. Elle est utilisée pour transférer des données entre le backend (serveur) et le frontend (client) + * tout en excluant les informations sensibles comme le mot de passe. + *

+ */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class UserResponseDTO { + + /** + * Identifiant unique de l'utilisateur. Il s'agit d'un UUID généré de manière unique. + */ + private UUID id; + + /** + * Nom de famille de l'utilisateur. C'est une donnée importante pour l'affichage du profil. + */ + private String nom; + + /** + * Prénom(s) de l'utilisateur. Représente le ou les prénoms associés à l'utilisateur. + */ + private String prenoms; + + /** + * Adresse email de l'utilisateur. C'est une donnée souvent utilisée pour les communications. + */ + private String email; + + /** + * URL de l'image de profil de l'utilisateur. Si l'utilisateur a une image de profil, cette URL + * pointe vers l'emplacement de l'image. + */ + private String profileImageUrl; + + /** + * Constructeur de DTO à partir d'une entité Users. + *

+ * Ce constructeur prend une entité {@link Users} et extrait les données nécessaires pour + * peupler les champs du DTO. Cette transformation permet de transférer des données sans exposer + * des informations sensibles. + *

+ * + * @param user L'entité {@link Users} dont les données sont extraites. + */ + public UserResponseDTO(Users user) { + if (user != null) { + this.id = user.getId(); // Identifiant unique de l'utilisateur + this.nom = user.getNom(); // Nom de famille + this.prenoms = user.getPrenoms(); // Prénom(s) + this.email = user.getEmail(); // Email + this.profileImageUrl = user.getProfileImageUrl(); // URL de l'image de profil + } + } +} diff --git a/src/main/java/com/lions/dev/entity/comment/Comment.java b/src/main/java/com/lions/dev/entity/comment/Comment.java index 04259e7..397128a 100644 --- a/src/main/java/com/lions/dev/entity/comment/Comment.java +++ b/src/main/java/com/lions/dev/entity/comment/Comment.java @@ -1,22 +1,21 @@ package com.lions.dev.entity.comment; import com.lions.dev.entity.BaseEntity; -import com.lions.dev.entity.users.Users; import com.lions.dev.entity.events.Events; +import com.lions.dev.entity.users.Users; import jakarta.persistence.*; +import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import java.time.LocalDateTime; - /** * Entité représentant un commentaire d'un utilisateur sur un événement dans le système AfterWork. - * Chaque commentaire est lié à un utilisateur et à un événement, et contient le texte du commentaire - * ainsi que la date de création. + * Chaque commentaire est lié à un utilisateur et à un événement, et contient le texte du + * commentaire ainsi que la date de création. * - * Des logs et des commentaires sont inclus pour assurer une traçabilité claire. + *

L'entité gère la relation entre les commentaires, les utilisateurs et les événements. */ @Entity @Table(name = "comments") @@ -30,7 +29,7 @@ public class Comment extends BaseEntity { private String text; // Le texte du commentaire @Column(name = "comment_date", nullable = false) - private LocalDateTime commentDate; // La date à laquelle le commentaire a été publié + private LocalDateTime commentDate; // La date de création du commentaire @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) @@ -43,26 +42,45 @@ public class Comment extends BaseEntity { /** * Constructeur pour créer un nouveau commentaire. * - * @param user L'utilisateur qui commente. - * @param event L'événement commenté. + *

Le constructeur initialise un commentaire avec l'utilisateur, l'événement et le texte + * fournis. Il définit également la date de création du commentaire. + * + * @param user L'utilisateur qui fait le commentaire. + * @param event L'événement auquel ce commentaire est lié. * @param text Le texte du commentaire. */ public Comment(Users user, Events event, String text) { this.user = user; this.event = event; this.text = text; - this.commentDate = LocalDateTime.now(); // Définit automatiquement la date actuelle - System.out.println("[LOG] Nouveau commentaire ajouté par " + user.getEmail() + " sur l'événement : " + event.getTitle() + " - Texte : " + text); + this.commentDate = + LocalDateTime.now(); // La date est définie automatiquement lors de la création + System.out.println( + "[LOG] Nouveau commentaire ajouté par " + + user.getEmail() + + " sur l'événement : " + + event.getTitle() + + " - Texte : " + + text); } /** * Modifie le texte du commentaire. * + *

Cette méthode permet de mettre à jour le texte d'un commentaire existant et de mettre à jour + * la date du commentaire pour refléter le changement. + * * @param newText Le nouveau texte du commentaire. */ public void updateComment(String newText) { - System.out.println("[LOG] Modification du commentaire de " + user.getEmail() + " sur l'événement : " + event.getTitle() + " - Nouveau texte : " + newText); + System.out.println( + "[LOG] Modification du commentaire de " + + user.getEmail() + + " sur l'événement : " + + event.getTitle() + + " - Nouveau texte : " + + newText); this.text = newText; - this.commentDate = LocalDateTime.now(); // Met à jour la date de modification + this.commentDate = LocalDateTime.now(); // Mise à jour de la date de modification } } 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 2c95050..cd1e7d1 100644 --- a/src/main/java/com/lions/dev/entity/events/Events.java +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -1,8 +1,10 @@ package com.lions.dev.entity.events; import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.comment.Comment; import com.lions.dev.entity.users.Users; import jakarta.persistence.*; +import java.util.List; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -109,4 +111,17 @@ public class Events extends BaseEntity { System.out.println("[LOG] Statut de l'événement mis à jour : " + this.title + " - " + this.status); } + @OneToMany(fetch = FetchType.LAZY, mappedBy = "event") + private List comments; // Liste des commentaires associés à l'événement + + /** + * Retourne la liste des commentaires associés à cet événement. + * + * @return Une liste de commentaires. + */ + public List getComments() { + System.out.println("[LOG] Récupération des commentaires pour l'événement : " + this.title); + return comments; + } + } diff --git a/src/main/java/com/lions/dev/entity/users/Users.java b/src/main/java/com/lions/dev/entity/users/Users.java index 545b1f2..5da1c15 100644 --- a/src/main/java/com/lions/dev/entity/users/Users.java +++ b/src/main/java/com/lions/dev/entity/users/Users.java @@ -1,7 +1,10 @@ package com.lions.dev.entity.users; import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.events.Events; import jakarta.persistence.*; +import java.util.HashSet; +import java.util.Set; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -41,6 +44,9 @@ public class Users extends BaseEntity { @Column(name = "profile_image_url") private String profileImageUrl; // L'URL de l'image de profil de l'utilisateur + @Column(name = "preferred_category") + private String preferredCategory; // La catégorie préférée de l'utilisateur + // Utilisation de BCrypt pour hacher les mots de passe de manière sécurisée private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); @@ -76,4 +82,49 @@ public class Users extends BaseEntity { System.out.println("[LOG] Vérification du rôle ADMIN pour l'utilisateur : " + this.email + " - Résultat : " + isAdmin); return isAdmin; } + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "favorite_events") + private Set favoriteEvents = new HashSet<>(); // Liste des événements favoris + + /** + * Ajoute un événement aux favoris de l'utilisateur. + * + * @param event L'événement à ajouter. + */ + public void addFavoriteEvent(Events event) { + favoriteEvents.add(event); + System.out.println("[LOG] Événement ajouté aux favoris pour l'utilisateur : " + this.email); + } + + /** + * Retourne la liste des événements favoris de l'utilisateur. + * + * @return Une liste d'événements favoris. + */ + public Set getFavoriteEvents() { + System.out.println("[LOG] Récupération des événements favoris pour l'utilisateur : " + this.email); + return favoriteEvents; + } + + /** + * Retourne la catégorie préférée de l'utilisateur. + * + * @return La catégorie préférée de l'utilisateur. + */ + public String getPreferredCategory() { + System.out.println("[LOG] Récupération de la catégorie préférée pour l'utilisateur : " + this.email); + return preferredCategory; + } + + /** + * Définit la catégorie préférée de l'utilisateur. + * + * @param category La catégorie à définir. + */ + public void setPreferredCategory(String category) { + this.preferredCategory = category; + System.out.println("[LOG] Catégorie préférée définie pour l'utilisateur : " + this.email + " - Catégorie : " + category); + } + } diff --git a/src/main/java/com/lions/dev/repository/FriendshipRepository.java b/src/main/java/com/lions/dev/repository/FriendshipRepository.java index 6394d8e..7661c60 100644 --- a/src/main/java/com/lions/dev/repository/FriendshipRepository.java +++ b/src/main/java/com/lions/dev/repository/FriendshipRepository.java @@ -5,7 +5,6 @@ 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 java.util.List; import java.util.Optional; import java.util.UUID; @@ -37,9 +36,15 @@ public class FriendshipRepository implements PanacheRepositoryBase findFriendsByUser(Users user, int page, int size) { - return find("(user = ?1 or friend = ?1) and status = ?2", user, FriendshipStatus.ACCEPTED) + 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) .page(page, size) - .list(); + .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 + .toList(); } /** diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 24b9883..8d00abc 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -1,32 +1,43 @@ package com.lions.dev.resource; -import com.lions.dev.service.EventService; -import com.lions.dev.repository.EventsRepository; +import com.lions.dev.core.errors.exceptions.EventNotFoundException; +import com.lions.dev.dto.UserResponseDTO; import com.lions.dev.dto.request.events.EventCreateRequestDTO; +import com.lions.dev.dto.request.events.EventReadManyByIdRequestDTO; import com.lions.dev.dto.request.events.EventUpdateRequestDTO; +import com.lions.dev.dto.response.comments.CommentResponseDTO; import com.lions.dev.dto.response.events.EventCreateResponseDTO; +import com.lions.dev.dto.response.events.EventReadManyByIdResponseDTO; import com.lions.dev.dto.response.events.EventUpdateResponseDTO; +import com.lions.dev.dto.response.friends.FriendshipReadFriendDetailsResponseDTO; +import com.lions.dev.entity.comment.Comment; import com.lions.dev.entity.events.Events; import com.lions.dev.entity.users.Users; -import com.lions.dev.repository.UsersRepository; // Ajout du UsersRepository pour gérer les +import com.lions.dev.repository.EventsRepository; +import com.lions.dev.repository.UsersRepository; +import com.lions.dev.service.EventService; +import com.lions.dev.service.FriendshipService; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; -import java.io.File; // participants +import java.io.File; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; -import com.lions.dev.core.errors.exceptions.EventNotFoundException; +import java.util.stream.Collectors; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.logging.Logger; /** - * Ressource REST pour la gestion des événements dans le système AfterWork. Cette classe expose des - * endpoints pour créer, récupérer, et supprimer des événements. + * Ressource REST pour la gestion des événements dans le système AfterWork. + * Cette classe expose des endpoints pour créer, récupérer, mettre à jour et supprimer des événements. * - *

Tous les logs nécessaires pour la traçabilité sont intégrés. + * Tous les logs nécessaires pour la traçabilité sont intégrés. */ @Path("/events") @Produces("application/json") @@ -38,116 +49,59 @@ public class EventsResource { EventsRepository eventsRepository; @Inject - UsersRepository usersRepository; // Ajout pour la gestion des participants + UsersRepository usersRepository; @Inject EventService eventService; + + @Inject + FriendshipService friendshipService; private static final Logger LOG = Logger.getLogger(EventsResource.class); - /** - * Endpoint pour créer un nouvel événement. - * - * @param eventCreateRequestDTO Le DTO contenant les informations de l'événement à créer. - * @return Une réponse HTTP contenant l'événement créé ou un message d'erreur. - */ + // *********** Création d'un événement *********** + @POST @Transactional - @Operation( - summary = "Créer un nouvel événement", - description = "Crée un nouvel événement et retourne ses détails") + @Operation(summary = "Créer un nouvel événement", description = "Crée un nouvel événement et retourne ses détails") public Response createEvent(EventCreateRequestDTO eventCreateRequestDTO) { - LOG.info( - "[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); - - // Récupérer l'utilisateur créateur à partir de l'identifiant + LOG.info("[LOG] Tentative de création d'un nouvel événement : " + eventCreateRequestDTO.getTitle()); Users creator = usersRepository.findById(eventCreateRequestDTO.getCreatorId()); if (creator == null) { LOG.error("[ERROR] Créateur non trouvé avec l'ID : " + eventCreateRequestDTO.getCreatorId()); return Response.status(Response.Status.BAD_REQUEST).entity("Créateur non trouvé").build(); } - - // Appel au service pour créer l'événement Events event = eventService.createEvent(eventCreateRequestDTO, creator); LOG.info("[LOG] Événement créé avec succès : " + event.getTitle()); - EventCreateResponseDTO responseDTO = new EventCreateResponseDTO(event); return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } - /** - * Endpoint pour récupérer les détails d'un événement par ID. - * - * @param id L'ID de l'événement. - * @return Une réponse HTTP contenant les informations de l'événement. - */ + // *********** Récupération d'un événement par ID *********** + @GET @Path("/{id}") - @Operation( - summary = "Récupérer un événement par ID", - description = "Retourne les détails de l'événement demandé") + @Operation(summary = "Récupérer un événement par ID", description = "Retourne les détails de l'événement demandé") public Response getEventById(@PathParam("id") UUID id) { LOG.info("[LOG] Récupération de l'événement avec l'ID : " + id); - Events event = eventsRepository.findById(id); if (event == null) { LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } - EventCreateResponseDTO responseDTO = new EventCreateResponseDTO(event); LOG.info("[LOG] Événement trouvé : " + event.getTitle()); return Response.ok(responseDTO).build(); } - /** - * Endpoint pour récupérer une liste de tous les événements après une date donnée. - * - * @param startDate La date de début à partir de laquelle filtrer les événements. - * @return Une réponse HTTP contenant la liste des événements après cette date. - */ - @GET - @Path("/after-date") - @Operation( - summary = "Récupérer les événements après une date", - description = "Retourne les événements après une date donnée") - public Response getEventsAfterDate(@QueryParam("startDate") LocalDateTime startDate) { - LOG.info("[LOG] Récupération des événements après la date : " + startDate); + // *********** Suppression d'un événement *********** - // Appel au service pour récupérer les événements après une date donnée - List events = eventService.getEventsAfterDate(startDate); - if (events.isEmpty()) { - LOG.warn("[LOG] Aucun événement trouvé après la date : " + startDate); - return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé après cette date.") - .build(); - } - - // Transformer la liste des événements en DTO pour la réponse - List responseDTOs = events.stream() - .map(EventCreateResponseDTO::new) - .toList(); - LOG.info("[LOG] Nombre d'événements trouvés après la date : " + events.size()); - - return Response.ok(responseDTOs).build(); - } - - /** - * Endpoint pour supprimer un événement par ID. - * - * @param id L'ID de l'événement à supprimer. - * @return Une réponse HTTP indiquant le succès ou l'échec de la suppression. - */ @DELETE @Path("/{id}") @Transactional - @Operation( - summary = "Supprimer un événement", - description = "Supprime un événement de la base de données") + @Operation(summary = "Supprimer un événement", description = "Supprime un événement de la base de données") public Response deleteEvent(@PathParam("id") UUID id) { LOG.info("Tentative de suppression de l'événement avec l'ID : " + id); - - // Appel du service pour la suppression de l'événement try { boolean deleted = eventService.deleteEvent(id); if (deleted) { @@ -163,176 +117,62 @@ public class EventsResource { } } + // *********** Ajouter un participant à un événement *********** - /** - * Endpoint pour ajouter un participant à un événement. - * - * @param eventId L'ID de l'événement. - * @param user L'utilisateur à ajouter comme participant. - * @return Une réponse HTTP indiquant le succès de l'ajout. - */ @POST @Path("/{id}/participants") @Transactional - @Operation( - summary = "Ajouter un participant à un événement", - description = "Ajoute un utilisateur à un événement") + @Operation(summary = "Ajouter un participant à un événement", description = "Ajoute un utilisateur à un événement") public Response addParticipant(@PathParam("id") UUID eventId, Users user) { LOG.info("Ajout d'un participant à l'événement : " + eventId); 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(); } - event.addParticipant(user); eventsRepository.persist(event); LOG.info("Participant ajouté avec succès à l'événement : " + event.getTitle()); return Response.ok(new EventCreateResponseDTO(event)).build(); } - /** - * Endpoint pour retirer un participant d'un événement. - * - * @param eventId L'ID de l'événement. - * @param userId L'ID de l'utilisateur à retirer. - * @return Une réponse HTTP indiquant le succès du retrait. - */ + // *********** Retirer un participant d'un événement *********** + @DELETE @Path("/{id}/participants/{userId}") @Transactional - @Operation( - summary = "Retirer un participant d'un événement", - description = "Supprime un utilisateur de la liste des participants d'un événement") - public Response removeParticipant( - @PathParam("id") UUID eventId, @PathParam("userId") UUID userId) { + @Operation(summary = "Retirer un participant d'un événement", description = "Supprime un utilisateur de la liste des participants d'un événement") + public Response removeParticipant(@PathParam("id") UUID eventId, @PathParam("userId") UUID userId) { LOG.info("Retrait d'un participant de l'événement : " + eventId); 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(); } - Users user = usersRepository.findById(userId); if (user == null) { LOG.warn("Utilisateur non trouvé avec l'ID : " + userId); return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); } - event.removeParticipant(user); eventsRepository.persist(event); LOG.info("Participant retiré avec succès de l'événement : " + event.getTitle()); return Response.noContent().build(); } - /** - * Endpoint pour obtenir le nombre de participants à un événement. - * - * @param eventId L'ID de l'événement. - * @return Le nombre de participants. - */ - @GET - @Path("/{id}/participants/count") - @Operation( - summary = "Obtenir le nombre de participants à un événement", - description = "Retourne le nombre total de participants à un événement") - public Response getNumberOfParticipants(@PathParam("id") UUID eventId) { - LOG.info("Récupération du nombre de participants pour l'événement : " + eventId); - Events event = eventsRepository.findById(eventId); + // *********** Mettre à jour un événement *********** - 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(); - } - - int participantCount = event.getNumberOfParticipants(); - LOG.info("Nombre de participants pour l'événement : " + participantCount); - return Response.ok(participantCount).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. - */ - @POST - @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); - 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(); - } - - event.setClosed(true); // Marquer l'événement comme fermé - eventsRepository.persist(event); - LOG.info("Événement fermé avec succès : " + event.getTitle()); - return Response.ok(new EventCreateResponseDTO(event)).build(); - } - - /** - * Endpoint pour réouvrir un événement. - * - * @param eventId L'ID de l'événement. - * @return Une réponse HTTP indiquant le succès de la réouverture. - */ - @POST - @Path("/{id}/reopen") - @Transactional - @Operation( - summary = "Réouvrir un événement", - description = "Réouvre un événement et permet à nouveau les participations") - public Response reopenEvent(@PathParam("id") UUID eventId) { - LOG.info("Tentative de réouverture de l'événement avec l'ID : " + eventId); - 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(); - } - - if ("ouvert".equals(event.getStatus())) { - LOG.warn("L'événement avec l'ID " + eventId + " est déjà ouvert."); - return Response.status(Response.Status.BAD_REQUEST).entity("L'événement est déjà ouvert.").build(); - } - - event.setStatus("ouvert"); // Marquer l'événement comme ouvert - eventsRepository.persist(event); - LOG.info("Événement réouvert avec succès : " + event.getTitle()); - return Response.ok(new EventCreateResponseDTO(event)).build(); - } - - - /** - * Endpoint pour mettre à jour un événement. - * - * @param id L'ID de l'événement. - * @param eventUpdateRequestDTO Le DTO de la requête de mise à jour. - * @return Une réponse HTTP indiquant la mise à jour. - */ @PUT @Path("/{id}") @Transactional @Operation(summary = "Mettre à jour un événement", description = "Modifie un événement existant") - public Response updateEvent( - @PathParam("id") UUID id, EventUpdateRequestDTO eventUpdateRequestDTO) { + public Response updateEvent(@PathParam("id") UUID id, EventUpdateRequestDTO eventUpdateRequestDTO) { LOG.info("[LOG] Tentative de mise à jour de l'événement avec l'ID : " + id); - Events event = eventsRepository.findById(id); if (event == null) { LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); } - // Mise à jour des attributs de l'événement event.setTitle(eventUpdateRequestDTO.getTitle()); event.setStartDate(eventUpdateRequestDTO.getStartDate()); @@ -342,88 +182,50 @@ public class EventsResource { event.setCategory(eventUpdateRequestDTO.getCategory()); event.setLink(eventUpdateRequestDTO.getLink()); event.setImageUrl(eventUpdateRequestDTO.getImageUrl()); - eventsRepository.persist(event); LOG.info("[LOG] Événement mis à jour avec succès : " + event.getTitle()); - EventUpdateResponseDTO responseDTO = new EventUpdateResponseDTO(event); return Response.ok(responseDTO).build(); } - /** - * Endpoint pour mettre à jour l'image d'un événement. - * - * @param id L'identifiant de l'événement. - * @param imageFilePath Le chemin vers l'image de l'événement. - * @return Un message indiquant si la mise à jour a réussi ou non. - */ - @PUT - @jakarta.ws.rs.Path("/{id}/image") - public String updateEventImage(@PathParam("id") UUID id, String imageFilePath) { + // *********** Récupérer les événements créés par un utilisateur spécifique et ses amis *********** + + @POST + @Path("/created-by-user-and-friends") + @Consumes("application/json") + @Produces("application/json") + @Operation(summary = "Récupérer les événements créés par un utilisateur et ses amis", description = "Retourne la liste des événements créés par un utilisateur spécifique et ses amis") + public Response getEventsCreatedByUserAndFriends(EventReadManyByIdRequestDTO requestDTO) { + UUID userId = requestDTO.getUserId(); + LOG.info("[LOG] Récupération des événements pour l'utilisateur avec l'ID : " + userId + " et ses amis"); + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + } try { - // Vérification si le chemin d'image est vide ou null - if (imageFilePath == null || imageFilePath.isEmpty()) { - System.out.println("[ERROR] Le chemin de l'image est vide ou null."); - return "Le chemin de l'image est vide ou null."; + List friends = friendshipService.listFriends(userId, 0, Integer.MAX_VALUE); + Set friendIds = friends.stream().map(FriendshipReadFriendDetailsResponseDTO::getFriendId).collect(Collectors.toSet()); + //friendIds = friendIds.stream().distinct().collect(Collectors.toSet()); + LOG.info("[LOG] IDs d'amis + utilisateur (taille attendue: " + friendIds.size() + ") : " + friendIds); + if (friendIds.isEmpty()) { + LOG.warn("[LOG] Aucun ami trouvé."); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun ami trouvé.").build(); } - - // Utiliser File pour vérifier si le fichier existe - File file = new File(imageFilePath); - if (!file.exists()) { - System.out.println("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); - return "Le fichier spécifié n'existe pas."; + List events = eventsRepository.find("creator.id IN ?1", friendIds).list(); + LOG.info("[LOG] Nombre d'événements récupérés dans la requête : " + events.size()); + if (events.isEmpty()) { + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé.").build(); } - - // Récupérer l'événement par son ID - Events event = eventService.getEventById(id); - if (event == null) { - System.out.println("[ERROR] Événement non trouvé avec l'ID : " + id); - return "Événement non trouvé."; - } - - // Mettre à jour l'URL de l'image de l'événement - String imageUrl = file.getAbsolutePath(); // Obtenir le chemin complet du fichier - event.setImageUrl(imageUrl); - - // Mise à jour de l'événement - eventService.updateEvent(event); - System.out.println( - "[LOG] Image de l'événement mise à jour avec succès pour : " + event.getTitle()); - - return "Image de l'événement mise à jour avec succès."; + List responseDTOs = events.stream().map(EventReadManyByIdResponseDTO::new).toList(); + return Response.ok(responseDTOs).build(); } catch (Exception e) { - System.out.println( - "[ERROR] Erreur lors de la mise à jour de l'image de l'événement : " + e.getMessage()); - return "Erreur lors de la mise à jour de l'image de l'événement."; + LOG.error("[ERROR] Erreur de récupération des événements : ", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("{\"message\": \"Erreur.\"}").build(); } } - /** - * Endpoint pour récupérer la liste de tous les événements. - * - * @return Une réponse HTTP contenant la liste des événements. - */ - @GET - @Operation( - summary = "Récupérer tous les événements", - description = "Retourne la liste de tous les événements disponibles") - public Response getAllEvents() { - LOG.info("[LOG] Récupération de tous les événements disponibles"); - - List events = eventsRepository.findAll().list(); - if (events.isEmpty()) { - LOG.warn("[LOG] Aucun événement trouvé."); - return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé.") - .build(); - } - - List responseDTOs = events.stream() - .map(EventCreateResponseDTO::new) - .toList(); - LOG.info("[LOG] Nombre total d'événements trouvés : " + events.size()); - return Response.ok(responseDTOs).build(); - } + // *********** Récupérer les événements par catégorie *********** /** * Endpoint pour récupérer les événements par catégorie. @@ -438,7 +240,6 @@ public class EventsResource { description = "Retourne la liste des événements correspondant à une catégorie donnée") public Response getEventsByCategory(@PathParam("category") String category) { LOG.info("[LOG] Récupération des événements dans la catégorie : " + category); - List events = eventService.findEventsByCategory(category); if (events.isEmpty()) { LOG.warn("[LOG] Aucun événement trouvé pour la catégorie : " + category); @@ -446,7 +247,6 @@ public class EventsResource { .entity("Aucun événement trouvé pour cette catégorie.") .build(); } - List responseDTOs = events.stream() .map(EventCreateResponseDTO::new) .toList(); @@ -454,126 +254,7 @@ public class EventsResource { return Response.ok(responseDTOs).build(); } - /** - * Endpoint pour mettre à jour le statut d'un événement. - * - * @param id L'ID de l'événement. - * @param status Le nouveau statut de l'événement. - * @return Une réponse HTTP indiquant la mise à jour du statut. - */ - @PUT - @Path("/{id}/status") - @Transactional - @Operation( - summary = "Mettre à jour le statut d'un événement", - description = "Modifie le statut d'un événement (ouvert, fermé, annulé, etc.)") - public Response updateEventStatus(@PathParam("id") UUID id, @QueryParam("status") String status) { - LOG.info("[LOG] Mise à jour du statut de l'événement avec l'ID : " + id); - - Events event = eventsRepository.findById(id); - if (event == null) { - LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); - return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); - } - - event.setStatus(status); - eventsRepository.persist(event); - LOG.info("[LOG] Statut de l'événement mis à jour avec succès : " + status); - - EventUpdateResponseDTO responseDTO = new EventUpdateResponseDTO(event); - return Response.ok(responseDTO).build(); - } - - /** - * Endpoint pour rechercher des événements par mots-clés. - * - * @param keyword Le mot-clé à rechercher. - * @return Une réponse HTTP contenant la liste des événements correspondant au mot-clé. - */ - @GET - @Path("/search") - @Operation( - summary = "Rechercher des événements par mots-clés", - description = "Retourne la liste des événements dont le titre ou la description contient les mots-clés spécifiés") - public Response searchEvents(@QueryParam("keyword") String keyword) { - LOG.info("[LOG] Recherche d'événements avec le mot-clé : " + keyword); - - List events = eventService.searchEvents(keyword); - if (events.isEmpty()) { - LOG.warn("[LOG] Aucun événement trouvé avec le mot-clé : " + keyword); - return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé pour ce mot-clé.") - .build(); - } - - List responseDTOs = events.stream() - .map(EventCreateResponseDTO::new) - .toList(); - LOG.info("[LOG] Nombre d'événements trouvés avec le mot-clé '" + keyword + "' : " + events.size()); - return Response.ok(responseDTOs).build(); - } - - /** - * Endpoint pour récupérer les événements auxquels un utilisateur est inscrit. - * - * @param userId L'ID de l'utilisateur. - * @return Une réponse HTTP contenant la liste des événements. - */ - @GET - @Path("/user/{userId}") - @Operation( - summary = "Récupérer les événements auxquels un utilisateur est inscrit", - description = "Retourne la liste des événements auxquels un utilisateur spécifique est inscrit") - public Response getEventsByUser(@PathParam("userId") UUID userId) { - LOG.info("[LOG] Récupération des événements pour l'utilisateur avec l'ID : " + userId); - - Users user = usersRepository.findById(userId); - if (user == null) { - LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); - return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); - } - - List events = eventService.findEventsByUser(user); - if (events.isEmpty()) { - LOG.warn("[LOG] Aucun événement trouvé pour l'utilisateur avec l'ID : " + userId); - return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé.").build(); - } - - List responseDTOs = events.stream() - .map(EventCreateResponseDTO::new) - .toList(); - LOG.info("[LOG] Nombre d'événements trouvés pour l'utilisateur : " + events.size()); - return Response.ok(responseDTOs).build(); - } - - /** - * Endpoint pour récupérer les événements par statut. - * - * @param status Le statut des événements à filtrer (en cours, terminé, etc.). - * @return Une réponse HTTP contenant la liste des événements avec ce statut. - */ - @GET - @Path("/status/{status}") - @Operation( - summary = "Récupérer les événements par statut", - description = "Retourne la liste des événements correspondant à un statut spécifique") - public Response getEventsByStatus(@PathParam("status") String status) { - LOG.info("[LOG] Récupération des événements avec le statut : " + status); - - List events = eventService.findEventsByStatus(status); - if (events.isEmpty()) { - LOG.warn("[LOG] Aucun événement trouvé avec le statut : " + status); - return Response.status(Response.Status.NOT_FOUND) - .entity("Aucun événement trouvé pour ce statut.") - .build(); - } - - List responseDTOs = events.stream() - .map(EventCreateResponseDTO::new) - .toList(); - LOG.info("[LOG] Nombre d'événements trouvés avec le statut '" + status + "' : " + events.size()); - return Response.ok(responseDTOs).build(); - } + // *********** Récupérer les événements entre deux dates *********** /** * Endpoint pour récupérer les événements entre deux dates spécifiques. @@ -592,16 +273,12 @@ public class EventsResource { @QueryParam("endDate") LocalDateTime endDate) { LOG.info("[LOG] Récupération des événements entre les dates : " + startDate + " et " + endDate); - - // Vérification de la validité des dates if (startDate == null || endDate == null || endDate.isBefore(startDate)) { LOG.error("[ERROR] Les dates fournies sont invalides."); return Response.status(Response.Status.BAD_REQUEST) .entity("Les dates sont invalides ou mal formatées.") .build(); } - - // Appel au service pour récupérer les événements entre les dates données List events = eventService.findEventsBetweenDates(startDate, endDate); if (events.isEmpty()) { LOG.warn("[LOG] Aucun événement trouvé entre les dates : " + startDate + " et " + endDate); @@ -609,8 +286,6 @@ public class EventsResource { .entity("Aucun événement trouvé entre ces dates.") .build(); } - - // Transformation des événements en DTO pour la réponse List responseDTOs = events.stream() .map(EventCreateResponseDTO::new) .toList(); @@ -618,4 +293,462 @@ public class EventsResource { return Response.ok(responseDTOs).build(); } + // *********** Récupérer les événements par statut *********** + + /** + * Endpoint pour récupérer les événements par statut. + * + * @param status Le statut des événements à filtrer (en cours, terminé, etc.). + * @return Une réponse HTTP contenant la liste des événements avec ce statut. + */ + @GET + @Path("/status/{status}") + @Operation( + summary = "Récupérer les événements par statut", + description = "Retourne la liste des événements correspondant à un statut spécifique") + public Response getEventsByStatus(@PathParam("status") String status) { + LOG.info("[LOG] Récupération des événements avec le statut : " + status); + List events = eventService.findEventsByStatus(status); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé avec le statut : " + status); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé pour ce statut.") + .build(); + } + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés avec le statut '" + status + "' : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + // *********** Rechercher des événements par mots-clés *********** + + /** + * Endpoint pour rechercher des événements par mots-clés. + * + * @param keyword Le mot-clé à rechercher. + * @return Une réponse HTTP contenant la liste des événements correspondant au mot-clé. + */ + @GET + @Path("/search") + @Operation( + summary = "Rechercher des événements par mots-clés", + description = "Retourne la liste des événements dont le titre ou la description contient les mots-clés spécifiés") + public Response searchEvents(@QueryParam("keyword") String keyword) { + LOG.info("[LOG] Recherche d'événements avec le mot-clé : " + keyword); + List events = eventService.searchEvents(keyword); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé avec le mot-clé : " + keyword); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé pour ce mot-clé.") + .build(); + } + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés avec le mot-clé '" + keyword + "' : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + // *********** Mettre à jour le statut d'un événement *********** + + /** + * Endpoint pour mettre à jour le statut d'un événement. + * + * @param id L'ID de l'événement. + * @param status Le nouveau statut de l'événement. + * @return Une réponse HTTP indiquant la mise à jour du statut. + */ + @PUT + @Path("/{id}/status") + @Transactional + @Operation( + summary = "Mettre à jour le statut d'un événement", + description = "Modifie le statut d'un événement (ouvert, fermé, annulé, etc.)") + public Response updateEventStatus(@PathParam("id") UUID id, @QueryParam("status") String status) { + LOG.info("[LOG] Mise à jour du statut de l'événement avec l'ID : " + id); + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + event.setStatus(status); + eventsRepository.persist(event); + LOG.info("[LOG] Statut de l'événement mis à jour avec succès : " + status); + EventUpdateResponseDTO responseDTO = new EventUpdateResponseDTO(event); + return Response.ok(responseDTO).build(); + } + + // *********** Récupérer les événements auxquels un utilisateur est inscrit *********** + + /** + * Endpoint pour récupérer les événements auxquels un utilisateur est inscrit. + * + * @param userId L'ID de l'utilisateur. + * @return Une réponse HTTP contenant la liste des événements. + */ + @GET + @Path("/user/{userId}") + @Operation( + summary = "Récupérer les événements auxquels un utilisateur est inscrit", + description = "Retourne la liste des événements auxquels un utilisateur spécifique est inscrit") + public Response getEventsByUser(@PathParam("userId") UUID userId) { + LOG.info("[LOG] Récupération des événements pour l'utilisateur avec l'ID : " + userId); + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + } + List events = eventService.findEventsByUser(user); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé pour l'utilisateur avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé.").build(); + } + List responseDTOs = events.stream() + .map(EventCreateResponseDTO::new) + .toList(); + LOG.info("[LOG] Nombre d'événements trouvés pour l'utilisateur : " + events.size()); + return Response.ok(responseDTOs).build(); + } + + // *********** Mettre à jour l'image d'un événement *********** + + /** + * Endpoint pour mettre à jour l'image d'un événement. + * + * @param id L'identifiant de l'événement. + * @param imageFilePath Le chemin vers l'image de l'événement. + * @return Un message indiquant si la mise à jour a réussi ou non. + */ + @PUT + @Path("/{id}/image") + public Response updateEventImage(@PathParam("id") UUID id, String imageFilePath) { + LOG.info("[LOG] Tentative de mise à jour de l'image pour l'événement avec l'ID : " + id); + + try { + if (imageFilePath == null || imageFilePath.isEmpty()) { + LOG.error("[ERROR] Le chemin de l'image est vide ou null."); + return Response.status(Response.Status.BAD_REQUEST).entity("Le chemin de l'image est vide ou null.").build(); + } + + File file = new File(imageFilePath); + if (!file.exists()) { + LOG.error("[ERROR] Le fichier spécifié n'existe pas : " + imageFilePath); + return Response.status(Response.Status.NOT_FOUND).entity("Le fichier spécifié n'existe pas.").build(); + } + + Events event = eventService.getEventById(id); + if (event == null) { + LOG.error("[ERROR] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + String imageUrl = file.getAbsolutePath(); + event.setImageUrl(imageUrl); + eventService.updateEvent(event); + + LOG.info("[LOG] Image de l'événement mise à jour avec succès pour : " + event.getTitle()); + return Response.ok("Image de l'événement mise à jour avec succès.").build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la mise à jour de l'image de l'événement : ", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Erreur lors de la mise à jour de l'image de l'événement.").build(); + } + } + + // *********** Mettre à jour partiellement un événement *********** + @PATCH + @Path("/{id}/partial-update") + @Transactional + @Operation(summary = "Mettre à jour partiellement un événement", description = "Mise à jour partielle des informations d'un événement") + public Response partialUpdateEvent(@PathParam("id") UUID id, Map updates) { + LOG.info("[LOG] Tentative de mise à jour partielle de l'événement avec l'ID : " + id); + + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + updates.forEach((field, value) -> { + // Mise à jour des champs dynamiquement, à adapter selon la structure de l'événement + // Exemple d'utilisation de réflexion si applicable + }); + + eventsRepository.persist(event); + LOG.info("[LOG] Événement mis à jour partiellement avec succès : " + event.getTitle()); + return Response.ok(new EventUpdateResponseDTO(event)).build(); + } + + // *********** Récupérer les événements à venir *********** + @GET + @Path("/upcoming") + @Operation(summary = "Récupérer les événements à venir", description = "Retourne les événements futurs.") + public Response getUpcomingEvents() { + LOG.info("[LOG] Récupération des événements à venir."); + + List events = eventService.findUpcomingEvents(); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement futur trouvé."); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement futur trouvé.").build(); + } + + List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + return Response.ok(responseDTOs).build(); + } + + // *********** Récupérer les événements passés *********** + @GET + @Path("/past") + @Operation(summary = "Récupérer les événements passés", description = "Retourne les événements déjà terminés.") + public Response getPastEvents() { + LOG.info("[LOG] Récupération des événements passés."); + + List events = eventService.findPastEvents(); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement passé trouvé."); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement passé trouvé.").build(); + } + + List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + return Response.ok(responseDTOs).build(); + } + + // *********** Annuler un événement *********** + @POST + @Path("/{id}/cancel") + @Transactional + @Operation(summary = "Annuler un événement", description = "Annule un événement sans le supprimer.") + public Response cancelEvent(@PathParam("id") UUID id) { + LOG.info("[LOG] Annulation de l'événement avec l'ID : " + id); + + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + event.setStatus("Annulé"); + eventsRepository.persist(event); + LOG.info("[LOG] Événement annulé avec succès : " + event.getTitle()); + return Response.ok(new EventUpdateResponseDTO(event)).build(); + } + + // *********** Récupérer les événements par localisation *********** + @GET + @Path("/location/{location}") + @Operation(summary = "Récupérer les événements par localisation", description = "Retourne les événements situés à une localisation spécifique.") + public Response getEventsByLocation(@PathParam("location") String location) { + LOG.info("[LOG] Récupération des événements à la localisation : " + location); + + List events = eventService.findEventsByLocation(location); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement trouvé pour la localisation : " + location); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement trouvé pour cette localisation.").build(); + } + + List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + return Response.ok(responseDTOs).build(); + } + + // *********** Récupérer les événements populaires *********** + @GET + @Path("/popular") + @Operation(summary = "Récupérer les événements populaires", description = "Retourne les événements ayant le plus de participants.") + public Response getPopularEvents() { + LOG.info("[LOG] Récupération des événements populaires."); + + List events = eventService.findPopularEvents(); + if (events.isEmpty()) { + LOG.warn("[LOG] Aucun événement populaire trouvé."); + return Response.status(Response.Status.NOT_FOUND).entity("Aucun événement populaire trouvé.").build(); + } + + List responseDTOs = events.stream().map(EventCreateResponseDTO::new).toList(); + return Response.ok(responseDTOs).build(); + } + + // *********** Étendre la durée d'un événement *********** + @PATCH + @Path("/{id}/extend") + @Transactional + @Operation(summary = "Étendre la durée d'un événement", description = "Permet de modifier la date de fin d'un événement.") + public Response extendEventDuration(@PathParam("id") UUID id, LocalDateTime newEndDate) { + LOG.info("[LOG] Extension de la durée de l'événement avec l'ID : " + id); + + Events event = eventsRepository.findById(id); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + if (newEndDate.isBefore(event.getStartDate())) { + LOG.error("[ERROR] La nouvelle date de fin est antérieure à la date de début."); + return Response.status(Response.Status.BAD_REQUEST).entity("La nouvelle date de fin doit être postérieure à la date de début.").build(); + } + + event.setEndDate(newEndDate); + eventsRepository.persist(event); + LOG.info("[LOG] Durée de l'événement étendue avec succès : " + event.getTitle()); + return Response.ok(new EventUpdateResponseDTO(event)).build(); + } + + // *********** Inviter des utilisateurs à un événement *********** + @POST + @Path("/{id}/invite") + @Transactional + @Operation(summary = "Inviter des utilisateurs à un événement", description = "Envoie des invitations à des utilisateurs pour un événement.") + public Response inviteUsersToEvent(@PathParam("id") UUID eventId, Set userIds) { + LOG.info("[LOG] Invitation d'utilisateurs à l'événement : " + eventId); + + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + List invitedUsers = userIds.stream().map(usersRepository::findById).filter(u -> u != null).collect(Collectors.toList()); + invitedUsers.forEach(event::addParticipant); // Adapte pour ajouter en tant qu'invités, si nécessaire + eventsRepository.persist(event); + + LOG.info("[LOG] Utilisateurs invités avec succès à l'événement : " + event.getTitle()); + return Response.ok("Invitations envoyées avec succès.").build(); + } + + @GET + @Path("/{id}/participants") + @Operation(summary = "Récupérer la liste des participants d'un événement", description = "Retourne la liste des utilisateurs participant à un événement spécifique.") + public Response getParticipants(@PathParam("id") UUID eventId) { + // Log d'entrée de la méthode + LOG.info("[LOG] Récupération des participants de l'événement avec l'ID : " + eventId); + + // Recherche de l'événement + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + // Récupération de la liste des participants + Set participantsSet = event.getParticipants(); + if (participantsSet == null || participantsSet.isEmpty()) { + LOG.warn("[LOG] Aucun participant trouvé pour l'événement avec l'ID : " + eventId); + return Response.status(Response.Status.NO_CONTENT).entity("Aucun participant trouvé.").build(); + } + + // Conversion des participants en List + List participantsList = new ArrayList<>(participantsSet); + + // Conversion des participants en DTO pour la réponse + List responseDTOs = participantsList.stream() + .map(UserResponseDTO::new) // Conversion de chaque utilisateur en UserResponseDTO + .collect(Collectors.toList()); + + // Log de la taille de la liste des participants pour la traçabilité + LOG.info("[LOG] Nombre de participants récupérés pour l'événement avec l'ID : " + eventId + " : " + responseDTOs.size()); + + // Retourner la réponse avec les participants + return Response.ok(responseDTOs).build(); + } + + + @POST + @Path("/{id}/favorite") + @Transactional + @Operation(summary = "Marquer un événement comme favori", description = "Permet à un utilisateur de marquer un événement comme favori.") + public Response favoriteEvent(@PathParam("id") UUID eventId, @QueryParam("userId") UUID userId) { + LOG.info("[LOG] Marquage de l'événement comme favori pour l'utilisateur ID : " + userId); + + Events event = eventsRepository.findById(eventId); + Users user = usersRepository.findById(userId); + if (event == null || user == null) { + LOG.warn("[LOG] Événement ou utilisateur non trouvé."); + return Response.status(Response.Status.NOT_FOUND).entity("Événement ou utilisateur non trouvé.").build(); + } + + user.addFavoriteEvent(event); + usersRepository.persist(user); + return Response.ok("Événement marqué comme favori.").build(); + } + + @GET + @Path("/user/{userId}/favorites") + @Operation(summary = "Récupérer les événements favoris d'un utilisateur", description = "Retourne les événements marqués comme favoris par un utilisateur.") + public Response getFavoriteEvents(@PathParam("userId") UUID userId) { + LOG.info("[LOG] Récupération des événements favoris pour l'utilisateur ID : " + userId); + + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + } + + // Convertir Set en List + List favoriteEvents = new ArrayList<>(user.getFavoriteEvents()); + + // Mapper les événements en DTO + List responseDTOs = favoriteEvents.stream().map(EventCreateResponseDTO::new).toList(); + + return Response.ok(responseDTOs).build(); + } + + @GET + @Path("/{id}/comments") + @Operation(summary = "Récupérer les commentaires d'un événement", description = "Retourne la liste des commentaires associés à un événement.") + public Response getComments(@PathParam("id") UUID eventId) { + LOG.info("[LOG] Récupération des commentaires pour l'événement ID : " + eventId); + + // Recherche de l'événement + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + // Récupération des commentaires associés à l'événement + List comments = event.getComments(); + List responseDTOs = comments.stream() + .map(CommentResponseDTO::new) // Conversion de chaque commentaire en CommentResponseDTO + .collect(Collectors.toList()); + + LOG.info("[LOG] Nombre de commentaires récupérés pour l'événement avec l'ID : " + eventId + " : " + responseDTOs.size()); + + // Retourner la réponse avec les commentaires sous forme de DTO + return Response.ok(responseDTOs).build(); + } + + @GET + @Path("/recommendations/{userId}") + @Operation(summary = "Recommander des événements basés sur les intérêts", description = "Retourne une liste d'événements recommandés pour un utilisateur.") + public Response getEventRecommendations(@PathParam("userId") UUID userId) { + LOG.info("[LOG] Récupération des recommandations d'événements pour l'utilisateur ID : " + userId); + + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.warn("[LOG] Utilisateur non trouvé avec l'ID : " + userId); + return Response.status(Response.Status.NOT_FOUND).entity("Utilisateur non trouvé.").build(); + } + + List recommendedEvents = eventService.recommendEventsForUser(user); + List responseDTOs = recommendedEvents.stream().map(EventCreateResponseDTO::new).toList(); + + return Response.ok(responseDTOs).build(); + } + + @GET + @Path("/{id}/share-link") + @Operation(summary = "Partager un événement via un lien", description = "Génère un lien de partage pour un événement.") + public Response getShareLink(@PathParam("id") UUID eventId) { + LOG.info("[LOG] Génération du lien de partage pour l'événement ID : " + eventId); + + Events event = eventsRepository.findById(eventId); + if (event == null) { + LOG.warn("[LOG] Événement non trouvé avec l'ID : " + eventId); + return Response.status(Response.Status.NOT_FOUND).entity("Événement non trouvé.").build(); + } + + String shareLink = "https://lions.dev /events/" + eventId; + return Response.ok(Map.of("shareLink", shareLink)).build(); + } } + diff --git a/src/main/java/com/lions/dev/resource/FriendshipResource.java b/src/main/java/com/lions/dev/resource/FriendshipResource.java index 9ac70b3..6e89765 100644 --- a/src/main/java/com/lions/dev/resource/FriendshipResource.java +++ b/src/main/java/com/lions/dev/resource/FriendshipResource.java @@ -6,6 +6,7 @@ import com.lions.dev.dto.request.friends.FriendshipReadStatusRequestDTO; import com.lions.dev.dto.response.friends.FriendshipCreateOneResponseDTO; import com.lions.dev.dto.response.friends.FriendshipReadFriendDetailsResponseDTO; import com.lions.dev.dto.response.friends.FriendshipReadStatusResponseDTO; +import com.lions.dev.exception.UserNotFoundException; import com.lions.dev.service.FriendshipService; import jakarta.inject.Inject; import jakarta.validation.Valid; @@ -215,35 +216,39 @@ public class FriendshipResource { summary = "Récupérer la liste des amis", description = "Retourne la liste des amis d'un utilisateur avec pagination") @APIResponses({ - @APIResponse( - responseCode = "200", - description = "Liste des amis récupérée avec succès", - content = - @Content( - mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = FriendshipReadFriendDetailsResponseDTO.class))), - @APIResponse(responseCode = "404", description = "Utilisateur non trouvé"), - @APIResponse(responseCode = "500", description = "Erreur lors de la récupération des amis") + @APIResponse( + responseCode = "200", + description = "Liste des amis récupérée avec succès", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FriendshipReadFriendDetailsResponseDTO.class))), + @APIResponse(responseCode = "404", description = "Utilisateur non trouvé"), + @APIResponse(responseCode = "500", description = "Erreur lors de la récupération des amis") }) public Response listFriends( @PathParam("userId") UUID userId, @QueryParam("page") @DefaultValue("0") int page, @QueryParam("size") @DefaultValue("10") int size) { - logger.info( - "[LOG] Reçu une demande pour récupérer la liste des amis de l'utilisateur avec l'ID : " - + userId); + logger.info("[LOG] Reçu une demande pour récupérer la liste des amis de l'utilisateur avec l'ID : " + userId); try { - List friendships = - friendshipService.listFriends(userId, page, size); - logger.info("[LOG] Liste des amis récupérée avec succès."); + List friendships = friendshipService.listFriends(userId, page, size) + .stream() + .distinct() // Assure qu'il n'y a pas de doublons + .toList(); + + logger.info("[LOG] Liste des amis récupérée avec succès, nombre d'amis : " + friendships.size()); return Response.ok(friendships).build(); + } catch (UserNotFoundException e) { + logger.error("[ERROR] Utilisateur non trouvé : " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity("{\"message\": \"Utilisateur non trouvé.\"}") + .build(); } catch (Exception e) { - logger.error( - "[ERROR] Erreur lors de la récupération de la liste des amis : " + e.getMessage(), e); + logger.error("[ERROR] Erreur lors de la récupération de la liste des amis : " + e.getMessage(), e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("{\"message\": \"Erreur lors de la récupération des amis.\"}") - .build(); + .entity("{\"message\": \"Erreur lors de la récupération des amis.\"}") + .build(); } } diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java index c2ff8c2..329270c 100644 --- a/src/main/java/com/lions/dev/service/EventService.java +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -16,7 +16,8 @@ import java.util.UUID; /** * Service de gestion des événements. - * Ce service contient la logique métier pour la création, récupération et suppression des événements. + * Ce service contient la logique métier pour la création, récupération, mise à jour et suppression des événements. + * Chaque méthode est loguée pour assurer une traçabilité exhaustive des actions effectuées. */ @ApplicationScoped public class EventService { @@ -34,6 +35,7 @@ public class EventService { * @return L'événement créé. */ public Events createEvent(EventCreateRequestDTO eventCreateRequestDTO, Users creator) { + // Initialisation de l'entité Event avec les détails fournis Events event = new Events(); event.setTitle(eventCreateRequestDTO.getTitle()); event.setDescription(eventCreateRequestDTO.getDescription()); @@ -46,8 +48,9 @@ public class EventService { event.setCreator(creator); event.setStatus("ouvert"); + // Persiste l'événement dans la base de données eventsRepository.persist(event); - logger.info("[LOG] Événement créé avec succès : {}", event.getTitle()); + logger.info("[logger] Événement créé avec succès : {}", event.getTitle()); return event; } @@ -59,24 +62,28 @@ public class EventService { * @throws EventNotFoundException Si l'événement n'est pas trouvé. */ public Events getEventById(UUID id) { + logger.info("[logger] Tentative de récupération de l'événement avec l'ID : {}", id); Events event = eventsRepository.findById(id); + if (event == null) { logger.error("[ERROR] Événement non trouvé avec l'ID : {}", id); throw new EventNotFoundException(id); } - logger.info("[LOG] Événement trouvé avec l'ID : {}", id); + logger.info("[logger] Événement trouvé avec l'ID : {}", id); return event; } /** * Récupère tous les événements après une date donnée. * - * @param startDate La date de début de filtre. - * @return Une liste d'événements. + * @param startDate La date de début pour filtrer les événements. + * @return Une liste d'événements après cette date. */ public List getEventsAfterDate(LocalDateTime startDate) { + logger.info("[logger] Récupération des événements après la date : {}", startDate); + List events = eventsRepository.findEventsAfterDate(startDate); - logger.info("[LOG] Nombre d'événements trouvés après la date {} : {}", startDate, events.size()); + logger.info("[logger] Nombre d'événements trouvés après la date {} : {}", startDate, events.size()); return events; } @@ -85,16 +92,17 @@ public class EventService { * * @param id L'ID de l'événement à supprimer. * @return true si l'événement a été supprimé, false sinon. + * @throws EventNotFoundException Si l'événement n'est pas trouvé. */ @Transactional public boolean deleteEvent(UUID id) { - logger.info("[LOG] Tentative de suppression de l'événement avec l'ID : {}", id); + logger.info("[logger] Tentative de suppression de l'événement avec l'ID : {}", id); boolean deleted = eventsRepository.deleteById(id); if (deleted) { - logger.info("[LOG] Événement avec l'ID {} supprimé avec succès.", id); + logger.info("[logger] Événement avec l'ID {} supprimé avec succès.", id); } else { - logger.warn("[LOG] Échec de la suppression : événement avec l'ID {} introuvable.", id); + logger.warn("[logger] Échec de la suppression : événement avec l'ID {} introuvable.", id); throw new EventNotFoundException(id); } return deleted; @@ -103,11 +111,14 @@ public class EventService { /** * Met à jour un événement dans le système. * - * @param event L'événement à mettre à jour. + * @param event L'événement contenant les détails mis à jour. * @return L'événement mis à jour. + * @throws EventNotFoundException Si l'événement n'est pas trouvé. */ @Transactional public Events updateEvent(Events event) { + logger.info("[logger] Tentative de mise à jour de l'événement avec l'ID : {}", event.getId()); + Events existingEvent = eventsRepository.findById(event.getId()); if (existingEvent == null) { logger.error("[ERROR] Événement non trouvé avec l'ID : {}", event.getId()); @@ -125,8 +136,9 @@ public class EventService { existingEvent.setImageUrl(event.getImageUrl()); existingEvent.setStatus(event.getStatus()); + // Persiste les modifications dans la base de données eventsRepository.persist(existingEvent); - logger.info("[LOG] Événement mis à jour avec succès : {}", existingEvent.getTitle()); + logger.info("[logger] Événement mis à jour avec succès : {}", existingEvent.getTitle()); return existingEvent; } @@ -137,27 +149,36 @@ public class EventService { * @return La liste des événements dans cette catégorie. */ public List findEventsByCategory(String category) { - return eventsRepository.find("category", category).list(); + logger.info("[logger] Récupération des événements dans la catégorie : {}", category); + List events = eventsRepository.find("category", category).list(); + logger.info("[logger] Nombre d'événements trouvés dans la catégorie '{}' : {}", category, events.size()); + return events; } /** - * Recherche des événements par mot-clé. + * Recherche des événements par mot-clé dans le titre ou la description. * * @param keyword Le mot-clé à rechercher. * @return La liste des événements correspondant au mot-clé. */ public List searchEvents(String keyword) { - return eventsRepository.find("title like ?1 or description like ?1", "%" + keyword + "%").list(); + logger.info("[logger] Recherche d'événements avec le mot-clé : {}", keyword); + List events = eventsRepository.find("title like ?1 or description like ?1", "%" + keyword + "%").list(); + logger.info("[logger] Nombre d'événements trouvés pour le mot-clé '{}' : {}", keyword, events.size()); + return events; } /** - * Récupère les événements d'un utilisateur. + * Récupère les événements auxquels un utilisateur participe. * * @param user L'utilisateur pour lequel récupérer les événements. * @return La liste des événements auxquels l'utilisateur participe. */ public List findEventsByUser(Users user) { - return eventsRepository.find("participants", user).list(); + logger.info("[logger] Récupération des événements pour l'utilisateur avec l'ID : {}", user.getId()); + List events = eventsRepository.find("participants", user).list(); + logger.info("[logger] Nombre d'événements pour l'utilisateur avec l'ID {} : {}", user.getId(), events.size()); + return events; } /** @@ -167,17 +188,98 @@ public class EventService { * @return La liste des événements ayant ce statut. */ public List findEventsByStatus(String status) { - return eventsRepository.find("status", status).list(); + logger.info("[logger] Récupération des événements avec le statut : {}", status); + List events = eventsRepository.find("status", status).list(); + logger.info("[logger] Nombre d'événements avec le statut '{}' : {}", status, events.size()); + return events; } /** - * Récupère les événements entre deux dates. + * Récupère les événements qui se déroulent entre deux dates spécifiques. * * @param startDate La date de début. * @param endDate La date de fin. * @return La liste des événements entre ces deux dates. */ public List findEventsBetweenDates(LocalDateTime startDate, LocalDateTime endDate) { - return eventsRepository.findEventsBetweenDates(startDate, endDate); + logger.info("[logger] Récupération des événements entre les dates : {} et {}", startDate, endDate); + + // Vérifie la validité des dates fournies + if (startDate == null || endDate == null || endDate.isBefore(startDate)) { + logger.error("[ERROR] Dates invalides fournies : startDate={}, endDate={}", startDate, endDate); + throw new IllegalArgumentException("Les dates sont invalides ou mal formatées."); + } + + List events = eventsRepository.findEventsBetweenDates(startDate, endDate); + logger.info("[logger] Nombre d'événements trouvés entre les dates : {}", events.size()); + return events; + } + + + /** + * Récupère les événements futurs. + * + * @return Une liste d'événements à venir. + */ + public List findUpcomingEvents() { + logger.info("[logger] Récupération des événements futurs."); + LocalDateTime now = LocalDateTime.now(); + List events = eventsRepository.find("startDate > ?1", now).list(); + logger.info("[logger] Nombre d'événements futurs trouvés : " + events.size()); + return events; + } + + /** + * Récupère les événements passés. + * + * @return Une liste d'événements passés. + */ + public List findPastEvents() { + logger.info("[logger] Récupération des événements passés."); + LocalDateTime now = LocalDateTime.now(); + List events = eventsRepository.find("endDate < ?1", now).list(); + logger.info("[logger] Nombre d'événements passés trouvés : " + events.size()); + return events; + } + + /** + * Récupère les événements par localisation. + * + * @param location La localisation des événements. + * @return La liste des événements situés à cette localisation. + */ + public List findEventsByLocation(String location) { + logger.info("[logger] Récupération des événements pour la localisation : " + location); + List events = eventsRepository.find("location", location).list(); + logger.info("[logger] Nombre d'événements trouvés pour la localisation '" + location + "' : " + events.size()); + return events; + } + + /** + * Récupère les événements populaires en fonction du nombre de participants. + * + * @return Une liste d'événements populaires. + */ + public List findPopularEvents() { + logger.info("[logger] Récupération des événements populaires."); + List events = eventsRepository.listAll().stream() + .sorted((e1, e2) -> Integer.compare(e2.getNumberOfParticipants(), e1.getNumberOfParticipants())) + .limit(10) + .toList(); + logger.info("[logger] Nombre d'événements populaires trouvés : " + events.size()); + return events; + } + + /** + * Recommande des événements pour un utilisateur spécifique. + * + * @param user L'utilisateur pour lequel recommander des événements. + * @return La liste des événements recommandés. + */ + public List recommendEventsForUser(Users user) { + logger.info("[logger] Recommandation d'événements pour l'utilisateur : " + user.getEmail()); + List events = eventsRepository.find("category", user.getPreferredCategory()).list(); + logger.info("[logger] Nombre d'événements recommandés pour l'utilisateur : " + events.size()); + return events; } } diff --git a/src/main/java/com/lions/dev/service/FileService.java b/src/main/java/com/lions/dev/service/FileService.java index ff5f5a3..1f0d52e 100644 --- a/src/main/java/com/lions/dev/service/FileService.java +++ b/src/main/java/com/lions/dev/service/FileService.java @@ -1,23 +1,32 @@ package com.lions.dev.service; -import org.jboss.logging.Logger; +import com.lions.dev.repository.EventsRepository; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import org.jboss.logging.Logger; /** * Service pour la gestion des fichiers uploadés. * Ce service permet de sauvegarder et gérer les fichiers uploadés sur le serveur. + * + *

Toutes les actions sont loguées pour assurer une traçabilité complète. */ @ApplicationScoped public class FileService { - private static final Logger LOG = Logger.getLogger(FileService.class); + @Inject + EventsRepository eventsRepository; + /** - * Sauvegarde le fichier uploadé sur le serveur. + * Sauvegarde le fichier uploadé sur le serveur, avec création du répertoire de destination + * si nécessaire et gestion des erreurs de manière contrôlée. * * @param uploadedFilePath Le chemin temporaire du fichier uploadé. * @param destinationDir Le répertoire de destination où sauvegarder le fichier. @@ -26,10 +35,34 @@ public class FileService { * @throws IOException Si une erreur survient lors de la sauvegarde. */ public Path saveFile(Path uploadedFilePath, String destinationDir, String fileName) throws IOException { - Path destination = Paths.get(destinationDir, fileName); - Files.createDirectories(Paths.get(destinationDir)); // Crée le répertoire s'il n'existe pas - Files.copy(uploadedFilePath, destination); // Copie le fichier vers sa destination - LOG.info("Fichier sauvegardé avec succès : " + destination); - return destination; + Path destinationPath = Paths.get(destinationDir, fileName); + LOG.info("[LOG] Tentative de sauvegarde du fichier vers : " + destinationPath); + + if (Files.notExists(uploadedFilePath)) { + LOG.error("[ERROR] Le fichier uploadé n'existe pas : " + uploadedFilePath); + throw new IOException("Le fichier uploadé n'existe pas : " + uploadedFilePath); + } + + try { + Files.createDirectories(Paths.get(destinationDir)); + LOG.info("[LOG] Répertoire de destination créé ou déjà existant : " + destinationDir); + } catch (IOException e) { + LOG.error("[ERROR] Impossible de créer le répertoire de destination : " + destinationDir, e); + throw new IOException("Impossible de créer le répertoire de destination : " + destinationDir, e); + } + + try { + Files.copy(uploadedFilePath, destinationPath, StandardCopyOption.REPLACE_EXISTING); + LOG.info("[LOG] Fichier sauvegardé avec succès à l'emplacement : " + destinationPath); + } catch (FileAlreadyExistsException e) { + LOG.warn("[WARNING] Le fichier existe déjà, il sera remplacé : " + destinationPath); + Files.copy(uploadedFilePath, destinationPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + LOG.error("[ERROR] Erreur lors de la copie du fichier vers : " + destinationPath, e); + throw new IOException("Erreur lors de la sauvegarde du fichier : " + destinationPath, e); + } + + return destinationPath; } + } diff --git a/src/main/java/com/lions/dev/service/FriendshipService.java b/src/main/java/com/lions/dev/service/FriendshipService.java index 237bc2d..92fadba 100644 --- a/src/main/java/com/lions/dev/service/FriendshipService.java +++ b/src/main/java/com/lions/dev/service/FriendshipService.java @@ -16,11 +16,11 @@ import com.lions.dev.repository.UsersRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; -import org.jboss.logging.Logger; - +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; +import org.jboss.logging.Logger; /** * Service pour gérer les relations d'amitié. @@ -196,25 +196,29 @@ public class FriendshipService { throw new UserNotFoundException("Utilisateur introuvable."); } - // Récupérer les amitiés acceptées List friendships = friendshipRepository.findFriendsByUser(user, page, size); - logger.info("[LOG] " + friendships.size() + " amis récupérés."); + logger.info("[LOG] " + friendships.size() + " amis récupérés (avant filtrage des doublons)."); - // Ajouter un log pour chaque amitié récupérée - friendships.forEach(friendship -> logger.info("[LOG] Ami : " + friendship.getFriend().getEmail())); + // Utilisation d'un ensemble pour stocker des clés uniques basées sur les IDs des amis + Set uniqueFriendKeys = new HashSet<>(); return friendships.stream() - .map(friendship -> new FriendshipReadFriendDetailsResponseDTO( - friendship.getUser().getId(), - friendship.getFriend().getId(), - friendship.getFriend().getNom(), - friendship.getFriend().getPrenoms(), - friendship.getFriend().getEmail(), - friendship.getStatus(), - friendship.getCreatedAt(), - friendship.getUpdatedAt() - )) - .collect(Collectors.toList()); + .map(friendship -> { + Users friend = friendship.getUser().equals(user) ? friendship.getFriend() : friendship.getUser(); + return new FriendshipReadFriendDetailsResponseDTO( + user.getId(), + friend.getId(), + friend.getNom(), + friend.getPrenoms(), + friend.getEmail(), + friendship.getStatus(), + friendship.getCreatedAt(), + friendship.getUpdatedAt() + ); + }) + .filter(dto -> uniqueFriendKeys.add(dto.getUserId().toString() + "-" + dto.getFriendId().toString())) + .limit(size) // Limite la taille au paramètre 'size' requis + .toList(); } /** @@ -234,6 +238,6 @@ public class FriendshipService { List friendships = friendshipRepository.findByUserAndStatus(user, request.getStatus(), request.getPage() - 1, request.getSize()); logger.info("[LOG] " + friendships.size() + " demandes d'amitié récupérées."); - return friendships.stream().map(FriendshipReadStatusResponseDTO::new).collect(Collectors.toList()); + return friendships.stream().map(FriendshipReadStatusResponseDTO::new).toList(); } } From 2f33b0975389420da97e5c593e3e8ec6b16f631f Mon Sep 17 00:00:00 2001 From: DahoudG Date: Sun, 17 Nov 2024 22:58:38 +0000 Subject: [PATCH 8/8] 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 +