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(); } }