From 56d0aad6a6d5f5f7e950a72008cd5643b34d605b Mon Sep 17 00:00:00 2001 From: dahoud Date: Tue, 13 Jan 2026 20:45:13 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Syst=C3=A8me=20complet=20de=20gestion?= =?UTF-8?q?=20des=20=C3=A9tablissements=20(backend)=20-=20Entit=C3=A9s=20J?= =?UTF-8?q?PA=20pour=20Establishment,=20EstablishmentMedia,=20Establishmen?= =?UTF-8?q?tRating=20-=20DTOs=20pour=20cr=C3=A9ation,=20mise=20=C3=A0=20jo?= =?UTF-8?q?ur=20et=20r=C3=A9ponses=20-=20Repositories=20Panache=20pour=20a?= =?UTF-8?q?cc=C3=A8s=20aux=20donn=C3=A9es=20-=20Services=20avec=20logique?= =?UTF-8?q?=20m=C3=A9tier=20et=20validation=20-=20Resources=20REST=20avec?= =?UTF-8?q?=20tous=20les=20endpoints=20CRUD=20-=20Gestion=20des=20m=C3=A9d?= =?UTF-8?q?ias=20(photos/vid=C3=A9os)=20-=20Syst=C3=A8me=20de=20notation?= =?UTF-8?q?=20avec=20statistiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EstablishmentCreateRequestDTO.java | 49 +++ .../EstablishmentRatingRequestDTO.java | 25 ++ .../EstablishmentUpdateRequestDTO.java | 34 ++ .../EstablishmentMediaResponseDTO.java | 66 ++++ .../EstablishmentRatingResponseDTO.java | 37 +++ .../EstablishmentRatingStatsResponseDTO.java | 30 ++ .../EstablishmentResponseDTO.java | 81 +++++ .../entity/establishment/Establishment.java | 106 +++++++ .../establishment/EstablishmentMedia.java | 61 ++++ .../establishment/EstablishmentRating.java | 72 +++++ .../dev/entity/establishment/MediaType.java | 10 + .../EstablishmentMediaRepository.java | 35 ++ .../EstablishmentRatingRepository.java | 81 +++++ .../repository/EstablishmentRepository.java | 88 +++++ .../resource/EstablishmentMediaResource.java | 149 +++++++++ .../resource/EstablishmentRatingResource.java | 183 +++++++++++ .../dev/resource/EstablishmentResource.java | 300 ++++++++++++++++++ .../service/EstablishmentMediaService.java | 118 +++++++ .../service/EstablishmentRatingService.java | 167 ++++++++++ .../dev/service/EstablishmentService.java | 194 +++++++++++ 20 files changed, 1886 insertions(+) create mode 100644 src/main/java/com/lions/dev/dto/request/establishment/EstablishmentCreateRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/request/establishment/EstablishmentRatingRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/request/establishment/EstablishmentUpdateRequestDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/establishment/EstablishmentMediaResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingStatsResponseDTO.java create mode 100644 src/main/java/com/lions/dev/dto/response/establishment/EstablishmentResponseDTO.java create mode 100644 src/main/java/com/lions/dev/entity/establishment/Establishment.java create mode 100644 src/main/java/com/lions/dev/entity/establishment/EstablishmentMedia.java create mode 100644 src/main/java/com/lions/dev/entity/establishment/EstablishmentRating.java create mode 100644 src/main/java/com/lions/dev/entity/establishment/MediaType.java create mode 100644 src/main/java/com/lions/dev/repository/EstablishmentMediaRepository.java create mode 100644 src/main/java/com/lions/dev/repository/EstablishmentRatingRepository.java create mode 100644 src/main/java/com/lions/dev/repository/EstablishmentRepository.java create mode 100644 src/main/java/com/lions/dev/resource/EstablishmentMediaResource.java create mode 100644 src/main/java/com/lions/dev/resource/EstablishmentRatingResource.java create mode 100644 src/main/java/com/lions/dev/resource/EstablishmentResource.java create mode 100644 src/main/java/com/lions/dev/service/EstablishmentMediaService.java create mode 100644 src/main/java/com/lions/dev/service/EstablishmentRatingService.java create mode 100644 src/main/java/com/lions/dev/service/EstablishmentService.java diff --git a/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentCreateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentCreateRequestDTO.java new file mode 100644 index 0000000..a38abdd --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentCreateRequestDTO.java @@ -0,0 +1,49 @@ +package com.lions.dev.dto.request.establishment; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; +import java.util.UUID; + +/** + * DTO pour la création d'un établissement. + * Seuls les responsables d'établissement peuvent créer des établissements. + */ +@Getter +@Setter +public class EstablishmentCreateRequestDTO { + + @NotNull(message = "Le nom de l'établissement est obligatoire.") + @Size(min = 2, max = 200, message = "Le nom doit comporter entre 2 et 200 caractères.") + private String name; + + @NotNull(message = "Le type d'établissement est obligatoire.") + private String type; + + @NotNull(message = "L'adresse est obligatoire.") + private String address; + + @NotNull(message = "La ville est obligatoire.") + private String city; + + @NotNull(message = "Le code postal est obligatoire.") + private String postalCode; + + private String description; + private String phoneNumber; + private String email; + private String website; + private String imageUrl; + private Double rating; + private String priceRange; + private Integer capacity; + private String amenities; + private String openingHours; + private Double latitude; + private Double longitude; + + @NotNull(message = "L'identifiant du responsable est obligatoire.") + private UUID managerId; +} + diff --git a/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentRatingRequestDTO.java b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentRatingRequestDTO.java new file mode 100644 index 0000000..7f09a67 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentRatingRequestDTO.java @@ -0,0 +1,25 @@ +package com.lions.dev.dto.request.establishment; + +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; + +/** + * DTO pour soumettre ou modifier une note d'établissement. + */ +@Getter +@Setter +public class EstablishmentRatingRequestDTO { + + @NotNull(message = "La note est obligatoire.") + @Min(value = 1, message = "La note doit être au moins 1 étoile.") + @Max(value = 5, message = "La note ne peut pas dépasser 5 étoiles.") + private Integer rating; // Note de 1 à 5 + + @Size(max = 2000, message = "Le commentaire ne peut pas dépasser 2000 caractères.") + private String comment; // Commentaire optionnel +} + diff --git a/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentUpdateRequestDTO.java b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentUpdateRequestDTO.java new file mode 100644 index 0000000..e790e8b --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/establishment/EstablishmentUpdateRequestDTO.java @@ -0,0 +1,34 @@ +package com.lions.dev.dto.request.establishment; + +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; + +/** + * DTO pour la mise à jour d'un établissement. + */ +@Getter +@Setter +public class EstablishmentUpdateRequestDTO { + + @Size(min = 2, max = 200, message = "Le nom doit comporter entre 2 et 200 caractères.") + private String name; + + private String type; + private String address; + private String city; + private String postalCode; + private String description; + private String phoneNumber; + private String email; + private String website; + private String imageUrl; + private Double rating; + private String priceRange; + private Integer capacity; + private String amenities; + private String openingHours; + private Double latitude; + private Double longitude; +} + diff --git a/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentMediaResponseDTO.java b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentMediaResponseDTO.java new file mode 100644 index 0000000..1826bdc --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentMediaResponseDTO.java @@ -0,0 +1,66 @@ +package com.lions.dev.dto.response.establishment; + +import com.lions.dev.entity.establishment.EstablishmentMedia; +import lombok.Getter; + +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO pour renvoyer les informations d'un média d'établissement. + */ +@Getter +public class EstablishmentMediaResponseDTO { + + private String id; + private String establishmentId; + private String mediaUrl; + private String mediaType; // "PHOTO" ou "VIDEO" + private String thumbnailUrl; + private MediaUploaderDTO uploadedBy; + private LocalDateTime uploadedAt; + private Integer displayOrder; + + /** + * Constructeur qui transforme une entité EstablishmentMedia en DTO. + * + * @param media Le média à convertir en DTO. + */ + public EstablishmentMediaResponseDTO(EstablishmentMedia media) { + this.id = media.getId().toString(); + this.establishmentId = media.getEstablishment().getId().toString(); + this.mediaUrl = media.getMediaUrl(); + this.mediaType = media.getMediaType().name(); + this.thumbnailUrl = media.getThumbnailUrl(); + this.uploadedAt = media.getUploadedAt(); + this.displayOrder = media.getDisplayOrder(); + + if (media.getUploadedBy() != null) { + this.uploadedBy = new MediaUploaderDTO( + media.getUploadedBy().getId().toString(), + media.getUploadedBy().getPrenoms(), + media.getUploadedBy().getNom(), + media.getUploadedBy().getProfileImageUrl() + ); + } + } + + /** + * DTO interne pour les informations de l'uploader. + */ + @Getter + public static class MediaUploaderDTO { + private final String id; + private final String firstName; + private final String lastName; + private final String profileImageUrl; + + public MediaUploaderDTO(String id, String firstName, String lastName, String profileImageUrl) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.profileImageUrl = profileImageUrl; + } + } +} + diff --git a/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingResponseDTO.java b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingResponseDTO.java new file mode 100644 index 0000000..d515929 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingResponseDTO.java @@ -0,0 +1,37 @@ +package com.lions.dev.dto.response.establishment; + +import com.lions.dev.entity.establishment.EstablishmentRating; +import lombok.Getter; + +import java.time.LocalDateTime; + +/** + * DTO pour renvoyer les informations d'une note d'établissement. + */ +@Getter +public class EstablishmentRatingResponseDTO { + + private String id; + private String establishmentId; + private String userId; + private Integer rating; + private String comment; + private LocalDateTime ratedAt; + private LocalDateTime updatedAt; + + /** + * Constructeur qui transforme une entité EstablishmentRating en DTO. + * + * @param rating La note à convertir en DTO. + */ + public EstablishmentRatingResponseDTO(EstablishmentRating rating) { + this.id = rating.getId().toString(); + this.establishmentId = rating.getEstablishment().getId().toString(); + this.userId = rating.getUser().getId().toString(); + this.rating = rating.getRating(); + this.comment = rating.getComment(); + this.ratedAt = rating.getRatedAt(); + this.updatedAt = rating.getUpdatedAt(); + } +} + diff --git a/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingStatsResponseDTO.java b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingStatsResponseDTO.java new file mode 100644 index 0000000..e4843df --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentRatingStatsResponseDTO.java @@ -0,0 +1,30 @@ +package com.lions.dev.dto.response.establishment; + +import lombok.Getter; + +import java.util.Map; + +/** + * DTO pour renvoyer les statistiques de notation d'un établissement. + */ +@Getter +public class EstablishmentRatingStatsResponseDTO { + + private Double averageRating; // Note moyenne (0.0 à 5.0) + private Integer totalRatings; // Nombre total de notes + private Map distribution; // Distribution par étoile {5: 10, 4: 5, ...} + + /** + * Constructeur pour créer les statistiques de notation. + * + * @param averageRating La note moyenne + * @param totalRatings Le nombre total de notes + * @param distribution La distribution des notes par étoile + */ + public EstablishmentRatingStatsResponseDTO(Double averageRating, Integer totalRatings, Map distribution) { + this.averageRating = averageRating; + this.totalRatings = totalRatings; + this.distribution = distribution; + } +} + diff --git a/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentResponseDTO.java b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentResponseDTO.java new file mode 100644 index 0000000..65b9dad --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/establishment/EstablishmentResponseDTO.java @@ -0,0 +1,81 @@ +package com.lions.dev.dto.response.establishment; + +import com.lions.dev.entity.establishment.Establishment; +import lombok.Getter; +import java.time.LocalDateTime; +import java.util.UUID; + +/** + * DTO pour renvoyer les informations d'un établissement. + * Ce DTO est utilisé pour structurer les données retournées dans les réponses + * après les opérations sur les établissements (création, récupération, mise à jour). + */ +@Getter +public class EstablishmentResponseDTO { + + private String id; + private String name; + private String type; + private String address; + private String city; + private String postalCode; + private String description; + private String phoneNumber; + private String email; + private String website; + private String imageUrl; + private Double rating; // Déprécié, utiliser averageRating + private Double averageRating; // Note moyenne calculée + private Integer totalRatingsCount; // Nombre total de notes + private String priceRange; + private Integer capacity; + private String amenities; + private String openingHours; + private Double latitude; + private Double longitude; + private String managerId; + private String managerEmail; + private String managerFirstName; + private String managerLastName; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + + /** + * Constructeur qui transforme une entité Establishment en DTO. + * + * @param establishment L'établissement à convertir en DTO. + */ + public EstablishmentResponseDTO(Establishment establishment) { + this.id = establishment.getId().toString(); + this.name = establishment.getName(); + this.type = establishment.getType(); + this.address = establishment.getAddress(); + this.city = establishment.getCity(); + this.postalCode = establishment.getPostalCode(); + this.description = establishment.getDescription(); + this.phoneNumber = establishment.getPhoneNumber(); + this.email = establishment.getEmail(); + this.website = establishment.getWebsite(); + this.imageUrl = establishment.getImageUrl(); + this.rating = establishment.getRating(); // Déprécié + this.averageRating = establishment.getAverageRating(); + this.totalRatingsCount = establishment.getTotalRatingsCount(); + this.priceRange = establishment.getPriceRange(); + this.capacity = establishment.getCapacity(); + this.amenities = establishment.getAmenities(); + this.openingHours = establishment.getOpeningHours(); + this.latitude = establishment.getLatitude(); + this.longitude = establishment.getLongitude(); + + if (establishment.getManager() != null) { + this.managerId = establishment.getManager().getId().toString(); + this.managerEmail = establishment.getManager().getEmail(); + this.managerFirstName = establishment.getManager().getPrenoms(); + this.managerLastName = establishment.getManager().getNom(); + } + + this.createdAt = establishment.getCreatedAt(); + this.updatedAt = establishment.getUpdatedAt(); + } +} + diff --git a/src/main/java/com/lions/dev/entity/establishment/Establishment.java b/src/main/java/com/lions/dev/entity/establishment/Establishment.java new file mode 100644 index 0000000..8485169 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/establishment/Establishment.java @@ -0,0 +1,106 @@ +package com.lions.dev.entity.establishment; + +import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.users.Users; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Entité représentant un établissement dans le système AfterWork. + * Un établissement est un lieu physique (bar, restaurant, club, etc.) + * où peuvent se dérouler des événements Afterwork. + * Seuls les responsables d'établissement peuvent créer et gérer des établissements. + */ +@Entity +@Table(name = "establishments") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Establishment extends BaseEntity { + + @Column(name = "name", nullable = false) + private String name; // Le nom de l'établissement + + @Column(name = "type", nullable = false) + private String type; // Type d'établissement (bar, restaurant, club, etc.) + + @Column(name = "address", nullable = false) + private String address; // Adresse de l'établissement + + @Column(name = "city", nullable = false) + private String city; // Ville de l'établissement + + @Column(name = "postal_code", nullable = false) + private String postalCode; // Code postal + + @Column(name = "description", length = 2000) + private String description; // Description de l'établissement + + @Column(name = "phone_number") + private String phoneNumber; // Numéro de téléphone + + @Column(name = "email") + private String email; // Email de contact + + @Column(name = "website") + private String website; // Site web + + @Column(name = "image_url") + private String imageUrl; // URL de l'image de l'établissement + + @Column(name = "rating") + private Double rating; // Note moyenne sur 5 (déprécié, utiliser averageRating) + + @Column(name = "average_rating") + private Double averageRating; // Note moyenne calculée (0.0 à 5.0) + + @Column(name = "total_ratings_count") + private Integer totalRatingsCount; // Nombre total de notes + + @Column(name = "price_range") + private String priceRange; // Fourchette de prix (cheap, moderate, expensive, luxury) + + @Column(name = "capacity") + private Integer capacity; // Capacité maximale + + @Column(name = "amenities", length = 1000) + private String amenities; // Équipements (WiFi, Terrasse, Parking, etc.) - JSON ou séparés par virgule + + @Column(name = "opening_hours") + private String openingHours; // Heures d'ouverture + + @Column(name = "latitude") + private Double latitude; // Latitude pour la géolocalisation + + @Column(name = "longitude") + private Double longitude; // Longitude pour la géolocalisation + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "manager_id", nullable = false) + private Users manager; // Le responsable de l'établissement + + // Relations avec les médias et les notes + @OneToMany(mappedBy = "establishment", cascade = CascadeType.ALL, orphanRemoval = true) + private java.util.List medias = new java.util.ArrayList<>(); // Liste des médias de l'établissement + + @OneToMany(mappedBy = "establishment", cascade = CascadeType.ALL, orphanRemoval = true) + private java.util.List ratings = new java.util.ArrayList<>(); // Liste des notes de l'établissement + + /** + * Constructeur pour créer un établissement avec les informations de base. + */ + public Establishment(String name, String type, String address, String city, + String postalCode, Users manager) { + this.name = name; + this.type = type; + this.address = address; + this.city = city; + this.postalCode = postalCode; + this.manager = manager; + } +} + diff --git a/src/main/java/com/lions/dev/entity/establishment/EstablishmentMedia.java b/src/main/java/com/lions/dev/entity/establishment/EstablishmentMedia.java new file mode 100644 index 0000000..e63ab6e --- /dev/null +++ b/src/main/java/com/lions/dev/entity/establishment/EstablishmentMedia.java @@ -0,0 +1,61 @@ +package com.lions.dev.entity.establishment; + +import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.users.Users; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Entité représentant un média (photo ou vidéo) associé à un établissement. + * + * Un établissement peut avoir plusieurs médias pour promouvoir son établissement. + * Les médias sont uploadés par le responsable de l'établissement. + */ +@Entity +@Table(name = "establishment_media") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class EstablishmentMedia extends BaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "establishment_id", nullable = false) + private Establishment establishment; // L'établissement auquel ce média appartient + + @Column(name = "media_url", nullable = false, length = 1000) + private String mediaUrl; // URL du média (photo ou vidéo) + + @Enumerated(EnumType.STRING) + @Column(name = "media_type", nullable = false) + private MediaType mediaType; // Type de média (PHOTO ou VIDEO) + + @Column(name = "thumbnail_url", length = 1000) + private String thumbnailUrl; // URL de la miniature (pour les vidéos) + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "uploaded_by", nullable = false) + private Users uploadedBy; // L'utilisateur qui a uploadé le média + + @Column(name = "uploaded_at", nullable = false) + private java.time.LocalDateTime uploadedAt; // Date et heure d'upload + + @Column(name = "display_order", nullable = false) + private Integer displayOrder = 0; // Ordre d'affichage dans la galerie + + /** + * Constructeur pour créer un média avec les informations de base. + */ + public EstablishmentMedia(Establishment establishment, String mediaUrl, MediaType mediaType, Users uploadedBy) { + this.establishment = establishment; + this.mediaUrl = mediaUrl; + this.mediaType = mediaType; + this.uploadedBy = uploadedBy; + this.uploadedAt = java.time.LocalDateTime.now(); + this.displayOrder = 0; + } +} + diff --git a/src/main/java/com/lions/dev/entity/establishment/EstablishmentRating.java b/src/main/java/com/lions/dev/entity/establishment/EstablishmentRating.java new file mode 100644 index 0000000..25b25cf --- /dev/null +++ b/src/main/java/com/lions/dev/entity/establishment/EstablishmentRating.java @@ -0,0 +1,72 @@ +package com.lions.dev.entity.establishment; + +import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.users.Users; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Entité représentant une note donnée par un utilisateur à un établissement. + * + * Chaque utilisateur ne peut avoir qu'une seule note par établissement. + * La note est un entier entre 1 et 5 (étoiles). + */ +@Entity +@Table( + name = "establishment_ratings", + uniqueConstraints = { + @UniqueConstraint( + name = "uk_establishment_user_rating", + columnNames = {"establishment_id", "user_id"} + ) + } +) +@Getter +@Setter +@NoArgsConstructor +@ToString +public class EstablishmentRating extends BaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "establishment_id", nullable = false) + private Establishment establishment; // L'établissement noté + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private Users user; // L'utilisateur qui a donné la note + + @Column(name = "rating", nullable = false) + private Integer rating; // Note donnée (1 à 5 étoiles) + + @Column(name = "comment", length = 2000) + private String comment; // Commentaire optionnel accompagnant la note + + @Column(name = "rated_at", nullable = false, updatable = false) + private java.time.LocalDateTime ratedAt; // Date et heure de création de la note + + @Column(name = "updated_at") + private java.time.LocalDateTime updatedAt; // Date et heure de dernière modification + + /** + * Constructeur pour créer une note avec les informations de base. + */ + public EstablishmentRating(Establishment establishment, Users user, Integer rating) { + this.establishment = establishment; + this.user = user; + this.rating = rating; + this.ratedAt = java.time.LocalDateTime.now(); + } + + /** + * Met à jour la note et la date de modification. + */ + public void updateRating(Integer newRating, String newComment) { + this.rating = newRating; + this.comment = newComment; + this.updatedAt = java.time.LocalDateTime.now(); + } +} + diff --git a/src/main/java/com/lions/dev/entity/establishment/MediaType.java b/src/main/java/com/lions/dev/entity/establishment/MediaType.java new file mode 100644 index 0000000..3750ed1 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/establishment/MediaType.java @@ -0,0 +1,10 @@ +package com.lions.dev.entity.establishment; + +/** + * Enum représentant le type de média pour un établissement. + */ +public enum MediaType { + PHOTO, + VIDEO +} + diff --git a/src/main/java/com/lions/dev/repository/EstablishmentMediaRepository.java b/src/main/java/com/lions/dev/repository/EstablishmentMediaRepository.java new file mode 100644 index 0000000..9f79f5f --- /dev/null +++ b/src/main/java/com/lions/dev/repository/EstablishmentMediaRepository.java @@ -0,0 +1,35 @@ +package com.lions.dev.repository; + +import com.lions.dev.entity.establishment.EstablishmentMedia; +import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.List; +import java.util.UUID; + +/** + * Repository Panache pour les médias d'établissements. + */ +@ApplicationScoped +public class EstablishmentMediaRepository implements PanacheRepositoryBase { + + /** + * Récupère tous les médias d'un établissement, triés par ordre d'affichage. + * + * @param establishmentId L'ID de l'établissement + * @return Liste des médias de l'établissement + */ + public List findByEstablishmentId(UUID establishmentId) { + return find("establishment.id = ?1 ORDER BY displayOrder ASC", establishmentId).list(); + } + + /** + * Supprime tous les médias d'un établissement. + * + * @param establishmentId L'ID de l'établissement + */ + public void deleteByEstablishmentId(UUID establishmentId) { + delete("establishment.id = ?1", establishmentId); + } +} + diff --git a/src/main/java/com/lions/dev/repository/EstablishmentRatingRepository.java b/src/main/java/com/lions/dev/repository/EstablishmentRatingRepository.java new file mode 100644 index 0000000..ed096ef --- /dev/null +++ b/src/main/java/com/lions/dev/repository/EstablishmentRatingRepository.java @@ -0,0 +1,81 @@ +package com.lions.dev.repository; + +import com.lions.dev.entity.establishment.EstablishmentRating; +import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Repository Panache pour les notations d'établissements. + */ +@ApplicationScoped +public class EstablishmentRatingRepository implements PanacheRepositoryBase { + + /** + * Récupère la note d'un utilisateur pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @param userId L'ID de l'utilisateur + * @return La note de l'utilisateur ou null si pas encore noté + */ + public EstablishmentRating findByEstablishmentIdAndUserId(UUID establishmentId, UUID userId) { + return find("establishment.id = ?1 AND user.id = ?2", establishmentId, userId).firstResult(); + } + + /** + * Récupère toutes les notes d'un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return Liste des notes de l'établissement + */ + public List findByEstablishmentId(UUID establishmentId) { + return find("establishment.id = ?1 ORDER BY ratedAt DESC", establishmentId).list(); + } + + /** + * Calcule la note moyenne d'un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return La note moyenne (0.0 si aucune note) + */ + public Double calculateAverageRating(UUID establishmentId) { + List ratings = findByEstablishmentId(establishmentId); + if (ratings.isEmpty()) { + return 0.0; + } + return ratings.stream() + .mapToInt(EstablishmentRating::getRating) + .average() + .orElse(0.0); + } + + /** + * Calcule la distribution des notes pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return Map avec clé = nombre d'étoiles (1-5), valeur = nombre de notes + */ + public Map calculateRatingDistribution(UUID establishmentId) { + List ratings = findByEstablishmentId(establishmentId); + return ratings.stream() + .collect(Collectors.groupingBy( + EstablishmentRating::getRating, + Collectors.collectingAndThen(Collectors.counting(), Long::intValue) + )); + } + + /** + * Compte le nombre total de notes pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return Le nombre total de notes + */ + public Long countByEstablishmentId(UUID establishmentId) { + return count("establishment.id = ?1", establishmentId); + } +} + diff --git a/src/main/java/com/lions/dev/repository/EstablishmentRepository.java b/src/main/java/com/lions/dev/repository/EstablishmentRepository.java new file mode 100644 index 0000000..3732bba --- /dev/null +++ b/src/main/java/com/lions/dev/repository/EstablishmentRepository.java @@ -0,0 +1,88 @@ +package com.lions.dev.repository; + +import com.lions.dev.entity.establishment.Establishment; +import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; +import jakarta.enterprise.context.ApplicationScoped; +import java.util.List; +import java.util.UUID; +import org.jboss.logging.Logger; + +/** + * Repository pour l'entité Establishment. + * Ce repository gère les opérations de base (CRUD) sur les établissements. + */ +@ApplicationScoped +public class EstablishmentRepository implements PanacheRepositoryBase { + + private static final Logger LOG = Logger.getLogger(EstablishmentRepository.class); + + /** + * Récupère tous les établissements gérés par un responsable. + * + * @param managerId L'ID du responsable. + * @return Une liste d'établissements gérés par ce responsable. + */ + public List findByManagerId(UUID managerId) { + LOG.info("[LOG] Récupération des établissements du responsable : " + managerId); + List establishments = list("manager.id = ?1", managerId); + LOG.info("[LOG] Nombre d'établissements trouvés pour le responsable " + managerId + " : " + establishments.size()); + return establishments; + } + + /** + * Recherche des établissements par nom ou ville. + * + * @param query Le terme de recherche. + * @return Une liste d'établissements correspondant à la recherche. + */ + public List searchByNameOrCity(String query) { + LOG.info("[LOG] Recherche d'établissements avec la requête : " + query); + String searchPattern = "%" + query.toLowerCase() + "%"; + List establishments = list( + "LOWER(name) LIKE ?1 OR LOWER(city) LIKE ?1", + searchPattern + ); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Filtre les établissements par type. + * + * @param type Le type d'établissement. + * @return Une liste d'établissements du type spécifié. + */ + public List findByType(String type) { + LOG.info("[LOG] Filtrage des établissements par type : " + type); + List establishments = list("type = ?1", type); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Filtre les établissements par ville. + * + * @param city La ville. + * @return Une liste d'établissements dans cette ville. + */ + public List findByCity(String city) { + LOG.info("[LOG] Filtrage des établissements par ville : " + city); + List establishments = list("city = ?1", city); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Filtre les établissements par fourchette de prix. + * + * @param priceRange La fourchette de prix. + * @return Une liste d'établissements avec cette fourchette de prix. + */ + public List findByPriceRange(String priceRange) { + LOG.info("[LOG] Filtrage des établissements par fourchette de prix : " + priceRange); + List establishments = list("priceRange = ?1", priceRange); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } +} + diff --git a/src/main/java/com/lions/dev/resource/EstablishmentMediaResource.java b/src/main/java/com/lions/dev/resource/EstablishmentMediaResource.java new file mode 100644 index 0000000..f1bf04b --- /dev/null +++ b/src/main/java/com/lions/dev/resource/EstablishmentMediaResource.java @@ -0,0 +1,149 @@ +package com.lions.dev.resource; + +import com.lions.dev.dto.response.establishment.EstablishmentMediaResponseDTO; +import com.lions.dev.entity.establishment.EstablishmentMedia; +import com.lions.dev.entity.establishment.MediaType; +import com.lions.dev.service.EstablishmentMediaService; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.jboss.logging.Logger; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Ressource REST pour la gestion des médias d'établissements. + * Cette classe expose des endpoints pour uploader, récupérer et supprimer des médias. + */ +@Path("/establishments/{establishmentId}/media") +@Produces(jakarta.ws.rs.core.MediaType.APPLICATION_JSON) +@Consumes(jakarta.ws.rs.core.MediaType.APPLICATION_JSON) +@Tag(name = "Establishment Media", description = "Opérations liées aux médias des établissements") +public class EstablishmentMediaResource { + + @Inject + EstablishmentMediaService mediaService; + + private static final Logger LOG = Logger.getLogger(EstablishmentMediaResource.class); + + /** + * Récupère tous les médias d'un établissement. + */ + @GET + @Operation(summary = "Récupérer tous les médias d'un établissement", + description = "Retourne la liste de tous les médias (photos et vidéos) d'un établissement") + public Response getEstablishmentMedia(@PathParam("establishmentId") String establishmentId) { + LOG.info("Récupération des médias pour l'établissement : " + establishmentId); + + try { + UUID id = UUID.fromString(establishmentId); + List medias = mediaService.getMediaByEstablishmentId(id); + List responseDTOs = medias.stream() + .map(EstablishmentMediaResponseDTO::new) + .collect(Collectors.toList()); + return Response.ok(responseDTOs).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID d'établissement invalide : " + establishmentId); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID d'établissement invalide") + .build(); + } catch (Exception e) { + LOG.error("Erreur lors de la récupération des médias", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération des médias") + .build(); + } + } + + /** + * Upload un nouveau média pour un établissement. + */ + @POST + @Transactional + @Operation(summary = "Uploader un média pour un établissement", + description = "Upload un nouveau média (photo ou vidéo) pour un établissement") + public Response uploadMedia( + @PathParam("establishmentId") String establishmentId, + @QueryParam("mediaUrl") String mediaUrl, + @QueryParam("mediaType") String mediaTypeStr, + @QueryParam("uploadedByUserId") String uploadedByUserIdStr, + @QueryParam("thumbnailUrl") String thumbnailUrl) { + LOG.info("Upload d'un média pour l'établissement : " + establishmentId); + + try { + UUID id = UUID.fromString(establishmentId); + UUID uploadedByUserId = UUID.fromString(uploadedByUserIdStr); + + // Valider le type de média + MediaType mediaType; + try { + mediaType = MediaType.valueOf(mediaTypeStr.toUpperCase()); + } catch (IllegalArgumentException e) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("Type de média invalide. Utilisez PHOTO ou VIDEO") + .build(); + } + + EstablishmentMedia media = mediaService.uploadMedia(id, mediaUrl, mediaType, uploadedByUserId, thumbnailUrl); + EstablishmentMediaResponseDTO responseDTO = new EstablishmentMediaResponseDTO(media); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); + } catch (IllegalArgumentException e) { + LOG.error("Paramètres invalides : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("Paramètres invalides : " + e.getMessage()) + .build(); + } catch (RuntimeException e) { + LOG.error("Erreur lors de l'upload du média : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de l'upload du média", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de l'upload du média") + .build(); + } + } + + /** + * Supprime un média d'un établissement. + */ + @DELETE + @Path("/{mediaId}") + @Transactional + @Operation(summary = "Supprimer un média d'un établissement", + description = "Supprime un média spécifique d'un établissement") + public Response deleteMedia( + @PathParam("establishmentId") String establishmentId, + @PathParam("mediaId") String mediaId) { + LOG.info("Suppression du média " + mediaId + " de l'établissement " + establishmentId); + + try { + UUID establishmentUuid = UUID.fromString(establishmentId); + UUID mediaUuid = UUID.fromString(mediaId); + mediaService.deleteMedia(establishmentUuid, mediaUuid); + return Response.status(Response.Status.NO_CONTENT).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID invalide : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID invalide") + .build(); + } catch (RuntimeException e) { + LOG.error("Erreur lors de la suppression du média : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de la suppression du média", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la suppression du média") + .build(); + } + } +} + diff --git a/src/main/java/com/lions/dev/resource/EstablishmentRatingResource.java b/src/main/java/com/lions/dev/resource/EstablishmentRatingResource.java new file mode 100644 index 0000000..9a1b5a0 --- /dev/null +++ b/src/main/java/com/lions/dev/resource/EstablishmentRatingResource.java @@ -0,0 +1,183 @@ +package com.lions.dev.resource; + +import com.lions.dev.dto.request.establishment.EstablishmentRatingRequestDTO; +import com.lions.dev.dto.response.establishment.EstablishmentRatingResponseDTO; +import com.lions.dev.dto.response.establishment.EstablishmentRatingStatsResponseDTO; +import com.lions.dev.entity.establishment.EstablishmentRating; +import com.lions.dev.service.EstablishmentRatingService; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.validation.Valid; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.jboss.logging.Logger; + +import java.util.Map; +import java.util.UUID; + +/** + * Ressource REST pour la gestion des notations d'établissements. + * Cette classe expose des endpoints pour soumettre, modifier et récupérer les notes. + */ +@Path("/establishments/{establishmentId}/ratings") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Tag(name = "Establishment Ratings", description = "Opérations liées aux notations des établissements") +public class EstablishmentRatingResource { + + @Inject + EstablishmentRatingService ratingService; + + private static final Logger LOG = Logger.getLogger(EstablishmentRatingResource.class); + + /** + * Soumet une nouvelle note pour un établissement. + */ + @POST + @Transactional + @Operation(summary = "Soumettre une note pour un établissement", + description = "Soumet une nouvelle note (1 à 5 étoiles) pour un établissement") + public Response submitRating( + @PathParam("establishmentId") String establishmentId, + @QueryParam("userId") String userIdStr, + @Valid EstablishmentRatingRequestDTO requestDTO) { + LOG.info("Soumission d'une note pour l'établissement " + establishmentId + " par l'utilisateur " + userIdStr); + + try { + UUID id = UUID.fromString(establishmentId); + UUID userId = UUID.fromString(userIdStr); + + EstablishmentRating rating = ratingService.submitRating(id, userId, requestDTO); + EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID invalide : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID invalide : " + e.getMessage()) + .build(); + } catch (RuntimeException e) { + LOG.error("Erreur lors de la soumission de la note : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de la soumission de la note", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la soumission de la note") + .build(); + } + } + + /** + * Met à jour une note existante. + */ + @PUT + @Transactional + @Operation(summary = "Modifier une note existante", + description = "Met à jour une note existante pour un établissement") + public Response updateRating( + @PathParam("establishmentId") String establishmentId, + @QueryParam("userId") String userIdStr, + @Valid EstablishmentRatingRequestDTO requestDTO) { + LOG.info("Mise à jour de la note pour l'établissement " + establishmentId + " par l'utilisateur " + userIdStr); + + try { + UUID id = UUID.fromString(establishmentId); + UUID userId = UUID.fromString(userIdStr); + + EstablishmentRating rating = ratingService.updateRating(id, userId, requestDTO); + EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); + return Response.ok(responseDTO).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID invalide : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID invalide : " + e.getMessage()) + .build(); + } catch (RuntimeException e) { + LOG.error("Erreur lors de la mise à jour de la note : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de la mise à jour de la note", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la mise à jour de la note") + .build(); + } + } + + /** + * Récupère la note d'un utilisateur pour un établissement. + */ + @GET + @Path("/users/{userId}") + @Operation(summary = "Récupérer la note d'un utilisateur", + description = "Récupère la note donnée par un utilisateur spécifique pour un établissement") + public Response getUserRating( + @PathParam("establishmentId") String establishmentId, + @PathParam("userId") String userIdStr) { + LOG.info("Récupération de la note de l'utilisateur " + userIdStr + " pour l'établissement " + establishmentId); + + try { + UUID id = UUID.fromString(establishmentId); + UUID userId = UUID.fromString(userIdStr); + + EstablishmentRating rating = ratingService.getUserRating(id, userId); + if (rating == null) { + return Response.status(Response.Status.NOT_FOUND) + .entity("Note non trouvée") + .build(); + } + + EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating); + return Response.ok(responseDTO).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID invalide : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID invalide : " + e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de la récupération de la note", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération de la note") + .build(); + } + } + + /** + * Récupère les statistiques de notation d'un établissement. + */ + @GET + @Path("/stats") + @Operation(summary = "Récupérer les statistiques de notation", + description = "Récupère les statistiques de notation d'un établissement (moyenne, total, distribution)") + public Response getRatingStats(@PathParam("establishmentId") String establishmentId) { + LOG.info("Récupération des statistiques de notation pour l'établissement " + establishmentId); + + try { + UUID id = UUID.fromString(establishmentId); + Map stats = ratingService.getRatingStats(id); + + EstablishmentRatingStatsResponseDTO responseDTO = new EstablishmentRatingStatsResponseDTO( + (Double) stats.get("averageRating"), + (Integer) stats.get("totalRatingsCount"), + (Map) stats.get("ratingDistribution") + ); + return Response.ok(responseDTO).build(); + } catch (IllegalArgumentException e) { + LOG.error("ID invalide : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("ID invalide : " + e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("Erreur inattendue lors de la récupération des statistiques", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération des statistiques") + .build(); + } + } +} + diff --git a/src/main/java/com/lions/dev/resource/EstablishmentResource.java b/src/main/java/com/lions/dev/resource/EstablishmentResource.java new file mode 100644 index 0000000..dd1204d --- /dev/null +++ b/src/main/java/com/lions/dev/resource/EstablishmentResource.java @@ -0,0 +1,300 @@ +package com.lions.dev.resource; + +import com.lions.dev.dto.request.establishment.EstablishmentCreateRequestDTO; +import com.lions.dev.dto.request.establishment.EstablishmentUpdateRequestDTO; +import com.lions.dev.dto.response.establishment.EstablishmentResponseDTO; +import com.lions.dev.entity.establishment.Establishment; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.UsersRepository; +import com.lions.dev.service.EstablishmentService; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.validation.Valid; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.jboss.logging.Logger; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Ressource REST pour la gestion des établissements dans le système AfterWork. + * Cette classe expose des endpoints pour créer, récupérer, mettre à jour et supprimer des établissements. + * Seuls les responsables d'établissement peuvent créer et gérer des établissements. + */ +@Path("/establishments") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@Tag(name = "Establishments", description = "Opérations liées à la gestion des établissements") +public class EstablishmentResource { + + @Inject + EstablishmentService establishmentService; + + @Inject + UsersRepository usersRepository; + + private static final Logger LOG = Logger.getLogger(EstablishmentResource.class); + + // *********** Création d'un établissement *********** + + @POST + @Transactional + @Operation(summary = "Créer un nouvel établissement", + description = "Crée un nouvel établissement. Seuls les responsables d'établissement peuvent créer des établissements.") + public Response createEstablishment(@Valid EstablishmentCreateRequestDTO requestDTO) { + LOG.info("[LOG] Tentative de création d'un nouvel établissement : " + requestDTO.getName()); + + try { + // Vérifier que managerId est fourni + if (requestDTO.getManagerId() == null) { + LOG.error("[ERROR] managerId est obligatoire pour créer un établissement"); + return Response.status(Response.Status.BAD_REQUEST) + .entity("L'identifiant du responsable (managerId) est obligatoire") + .build(); + } + + // Récupérer le responsable + Users manager = usersRepository.findById(requestDTO.getManagerId()); + if (manager == null) { + LOG.error("[ERROR] Responsable non trouvé avec l'ID : " + requestDTO.getManagerId()); + return Response.status(Response.Status.BAD_REQUEST) + .entity("Responsable non trouvé avec l'ID fourni") + .build(); + } + + // Créer l'établissement + Establishment establishment = new Establishment(); + establishment.setName(requestDTO.getName()); + establishment.setType(requestDTO.getType()); + establishment.setAddress(requestDTO.getAddress()); + establishment.setCity(requestDTO.getCity()); + establishment.setPostalCode(requestDTO.getPostalCode()); + establishment.setDescription(requestDTO.getDescription()); + establishment.setPhoneNumber(requestDTO.getPhoneNumber()); + establishment.setEmail(requestDTO.getEmail()); + establishment.setWebsite(requestDTO.getWebsite()); + establishment.setImageUrl(requestDTO.getImageUrl()); + establishment.setRating(requestDTO.getRating()); + establishment.setPriceRange(requestDTO.getPriceRange()); + establishment.setCapacity(requestDTO.getCapacity()); + establishment.setAmenities(requestDTO.getAmenities()); + establishment.setOpeningHours(requestDTO.getOpeningHours()); + establishment.setLatitude(requestDTO.getLatitude()); + establishment.setLongitude(requestDTO.getLongitude()); + + Establishment createdEstablishment = establishmentService.createEstablishment(establishment, requestDTO.getManagerId()); + LOG.info("[LOG] Établissement créé avec succès : " + createdEstablishment.getName()); + + EstablishmentResponseDTO responseDTO = new EstablishmentResponseDTO(createdEstablishment); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); + } catch (RuntimeException e) { + LOG.error("[ERROR] Erreur lors de la création de l'établissement : " + e.getMessage()); + return Response.status(Response.Status.BAD_REQUEST) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur inattendue lors de la création de l'établissement", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la création de l'établissement") + .build(); + } + } + + // *********** Récupération de tous les établissements *********** + + @GET + @Operation(summary = "Récupérer tous les établissements", + description = "Retourne la liste de tous les établissements disponibles") + public Response getAllEstablishments() { + LOG.info("[LOG] Récupération de tous les établissements"); + try { + List establishments = establishmentService.getAllEstablishments(); + List responseDTOs = establishments.stream() + .map(EstablishmentResponseDTO::new) + .collect(Collectors.toList()); + return Response.ok(responseDTOs).build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la récupération des établissements", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération des établissements") + .build(); + } + } + + // *********** Récupération d'un établissement par ID *********** + + @GET + @Path("/{id}") + @Operation(summary = "Récupérer un établissement par ID", + description = "Retourne les détails de l'établissement demandé") + public Response getEstablishmentById(@PathParam("id") UUID id) { + LOG.info("[LOG] Récupération de l'établissement avec l'ID : " + id); + try { + Establishment establishment = establishmentService.getEstablishmentById(id); + EstablishmentResponseDTO responseDTO = new EstablishmentResponseDTO(establishment); + return Response.ok(responseDTO).build(); + } catch (RuntimeException e) { + LOG.warn("[WARN] " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la récupération de l'établissement", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération de l'établissement") + .build(); + } + } + + // *********** Recherche d'établissements *********** + + @GET + @Path("/search") + @Operation(summary = "Rechercher des établissements", + description = "Recherche des établissements par nom ou ville") + public Response searchEstablishments(@QueryParam("q") String query) { + LOG.info("[LOG] Recherche d'établissements avec la requête : " + query); + try { + if (query == null || query.trim().isEmpty()) { + return Response.status(Response.Status.BAD_REQUEST) + .entity("Le paramètre de recherche 'q' est obligatoire") + .build(); + } + List establishments = establishmentService.searchEstablishments(query); + List responseDTOs = establishments.stream() + .map(EstablishmentResponseDTO::new) + .collect(Collectors.toList()); + return Response.ok(responseDTOs).build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la recherche d'établissements", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la recherche d'établissements") + .build(); + } + } + + // *********** Filtrage d'établissements *********** + + @GET + @Path("/filter") + @Operation(summary = "Filtrer les établissements", + description = "Filtre les établissements par type, fourchette de prix et/ou ville") + public Response filterEstablishments( + @QueryParam("type") String type, + @QueryParam("priceRange") String priceRange, + @QueryParam("city") String city) { + LOG.info("[LOG] Filtrage des établissements : type=" + type + ", priceRange=" + priceRange + ", city=" + city); + try { + List establishments = establishmentService.filterEstablishments(type, priceRange, city); + List responseDTOs = establishments.stream() + .map(EstablishmentResponseDTO::new) + .collect(Collectors.toList()); + return Response.ok(responseDTOs).build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors du filtrage des établissements", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors du filtrage des établissements") + .build(); + } + } + + // *********** Récupération des établissements d'un responsable *********** + + @GET + @Path("/manager/{managerId}") + @Operation(summary = "Récupérer les établissements d'un responsable", + description = "Retourne tous les établissements gérés par un responsable") + public Response getEstablishmentsByManager(@PathParam("managerId") UUID managerId) { + LOG.info("[LOG] Récupération des établissements du responsable : " + managerId); + try { + List establishments = establishmentService.getEstablishmentsByManager(managerId); + List responseDTOs = establishments.stream() + .map(EstablishmentResponseDTO::new) + .collect(Collectors.toList()); + return Response.ok(responseDTOs).build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la récupération des établissements du responsable", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la récupération des établissements du responsable") + .build(); + } + } + + // *********** Mise à jour d'un établissement *********** + + @PUT + @Path("/{id}") + @Transactional + @Operation(summary = "Mettre à jour un établissement", + description = "Met à jour les informations d'un établissement existant") + public Response updateEstablishment( + @PathParam("id") UUID id, + @Valid EstablishmentUpdateRequestDTO requestDTO) { + LOG.info("[LOG] Mise à jour de l'établissement avec l'ID : " + id); + try { + Establishment establishment = new Establishment(); + establishment.setName(requestDTO.getName()); + establishment.setType(requestDTO.getType()); + establishment.setAddress(requestDTO.getAddress()); + establishment.setCity(requestDTO.getCity()); + establishment.setPostalCode(requestDTO.getPostalCode()); + establishment.setDescription(requestDTO.getDescription()); + establishment.setPhoneNumber(requestDTO.getPhoneNumber()); + establishment.setEmail(requestDTO.getEmail()); + establishment.setWebsite(requestDTO.getWebsite()); + establishment.setImageUrl(requestDTO.getImageUrl()); + establishment.setRating(requestDTO.getRating()); + establishment.setPriceRange(requestDTO.getPriceRange()); + establishment.setCapacity(requestDTO.getCapacity()); + establishment.setAmenities(requestDTO.getAmenities()); + establishment.setOpeningHours(requestDTO.getOpeningHours()); + establishment.setLatitude(requestDTO.getLatitude()); + establishment.setLongitude(requestDTO.getLongitude()); + + Establishment updatedEstablishment = establishmentService.updateEstablishment(id, establishment); + EstablishmentResponseDTO responseDTO = new EstablishmentResponseDTO(updatedEstablishment); + return Response.ok(responseDTO).build(); + } catch (RuntimeException e) { + LOG.error("[ERROR] " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la mise à jour de l'établissement", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la mise à jour de l'établissement") + .build(); + } + } + + // *********** Suppression d'un établissement *********** + + @DELETE + @Path("/{id}") + @Transactional + @Operation(summary = "Supprimer un établissement", + description = "Supprime un établissement du système") + public Response deleteEstablishment(@PathParam("id") UUID id) { + LOG.info("[LOG] Suppression de l'établissement avec l'ID : " + id); + try { + establishmentService.deleteEstablishment(id); + return Response.noContent().build(); + } catch (RuntimeException e) { + LOG.error("[ERROR] " + e.getMessage()); + return Response.status(Response.Status.NOT_FOUND) + .entity(e.getMessage()) + .build(); + } catch (Exception e) { + LOG.error("[ERROR] Erreur lors de la suppression de l'établissement", e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Erreur lors de la suppression de l'établissement") + .build(); + } + } +} + diff --git a/src/main/java/com/lions/dev/service/EstablishmentMediaService.java b/src/main/java/com/lions/dev/service/EstablishmentMediaService.java new file mode 100644 index 0000000..e01995f --- /dev/null +++ b/src/main/java/com/lions/dev/service/EstablishmentMediaService.java @@ -0,0 +1,118 @@ +package com.lions.dev.service; + +import com.lions.dev.entity.establishment.Establishment; +import com.lions.dev.entity.establishment.EstablishmentMedia; +import com.lions.dev.entity.establishment.MediaType; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.EstablishmentMediaRepository; +import com.lions.dev.repository.EstablishmentRepository; +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.UUID; + +/** + * Service de gestion des médias d'établissements. + * Ce service contient la logique métier pour l'upload, la récupération et la suppression des médias. + */ +@ApplicationScoped +public class EstablishmentMediaService { + + @Inject + EstablishmentMediaRepository mediaRepository; + + @Inject + EstablishmentRepository establishmentRepository; + + @Inject + UsersRepository usersRepository; + + private static final Logger LOG = Logger.getLogger(EstablishmentMediaService.class); + + /** + * Récupère tous les médias d'un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return Liste des médias de l'établissement + */ + public List getMediaByEstablishmentId(UUID establishmentId) { + LOG.info("Récupération des médias pour l'établissement : " + establishmentId); + return mediaRepository.findByEstablishmentId(establishmentId); + } + + /** + * Upload un nouveau média pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @param mediaUrl L'URL du média + * @param mediaType Le type de média (PHOTO ou VIDEO) + * @param uploadedByUserId L'ID de l'utilisateur qui upload + * @param thumbnailUrl L'URL de la miniature (optionnel, pour les vidéos) + * @return Le média créé + */ + @Transactional + public EstablishmentMedia uploadMedia(UUID establishmentId, String mediaUrl, MediaType mediaType, UUID uploadedByUserId, String thumbnailUrl) { + LOG.info("Upload d'un média pour l'établissement : " + establishmentId); + + // Vérifier que l'établissement existe + Establishment establishment = establishmentRepository.findById(establishmentId); + if (establishment == null) { + LOG.error("Établissement non trouvé avec l'ID : " + establishmentId); + throw new RuntimeException("Établissement non trouvé"); + } + + // Vérifier que l'utilisateur existe + Users uploadedBy = usersRepository.findById(uploadedByUserId); + if (uploadedBy == null) { + LOG.error("Utilisateur non trouvé avec l'ID : " + uploadedByUserId); + throw new RuntimeException("Utilisateur non trouvé"); + } + + // Créer le média + EstablishmentMedia media = new EstablishmentMedia(establishment, mediaUrl, mediaType, uploadedBy); + media.setThumbnailUrl(thumbnailUrl); + + // Déterminer l'ordre d'affichage (dernier média = ordre le plus élevé) + List existingMedia = mediaRepository.findByEstablishmentId(establishmentId); + int maxOrder = existingMedia.stream() + .mapToInt(EstablishmentMedia::getDisplayOrder) + .max() + .orElse(-1); + media.setDisplayOrder(maxOrder + 1); + + mediaRepository.persist(media); + LOG.info("Média uploadé avec succès : " + media.getId()); + return media; + } + + /** + * Supprime un média d'un établissement. + * + * @param establishmentId L'ID de l'établissement + * @param mediaId L'ID du média à supprimer + */ + @Transactional + public void deleteMedia(UUID establishmentId, UUID mediaId) { + LOG.info("Suppression du média " + mediaId + " de l'établissement " + establishmentId); + + EstablishmentMedia media = mediaRepository.findById(mediaId); + if (media == null) { + LOG.error("Média non trouvé avec l'ID : " + mediaId); + throw new RuntimeException("Média non trouvé"); + } + + // Vérifier que le média appartient à l'établissement + if (!media.getEstablishment().getId().equals(establishmentId)) { + LOG.error("Le média " + mediaId + " n'appartient pas à l'établissement " + establishmentId); + throw new RuntimeException("Le média n'appartient pas à cet établissement"); + } + + mediaRepository.delete(media); + LOG.info("Média supprimé avec succès : " + mediaId); + } +} + diff --git a/src/main/java/com/lions/dev/service/EstablishmentRatingService.java b/src/main/java/com/lions/dev/service/EstablishmentRatingService.java new file mode 100644 index 0000000..b12120e --- /dev/null +++ b/src/main/java/com/lions/dev/service/EstablishmentRatingService.java @@ -0,0 +1,167 @@ +package com.lions.dev.service; + +import com.lions.dev.dto.request.establishment.EstablishmentRatingRequestDTO; +import com.lions.dev.entity.establishment.Establishment; +import com.lions.dev.entity.establishment.EstablishmentRating; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.EstablishmentRatingRepository; +import com.lions.dev.repository.EstablishmentRepository; +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.Map; +import java.util.UUID; + +/** + * Service de gestion des notations d'établissements. + * Ce service contient la logique métier pour soumettre, modifier et récupérer les notes. + */ +@ApplicationScoped +public class EstablishmentRatingService { + + @Inject + EstablishmentRatingRepository ratingRepository; + + @Inject + EstablishmentRepository establishmentRepository; + + @Inject + UsersRepository usersRepository; + + private static final Logger LOG = Logger.getLogger(EstablishmentRatingService.class); + + /** + * Soumet une nouvelle note pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @param userId L'ID de l'utilisateur + * @param requestDTO Le DTO contenant la note et le commentaire + * @return La note créée + */ + @Transactional + public EstablishmentRating submitRating(UUID establishmentId, UUID userId, EstablishmentRatingRequestDTO requestDTO) { + LOG.info("Soumission d'une note pour l'établissement " + establishmentId + " par l'utilisateur " + userId); + + // Vérifier que l'établissement existe + Establishment establishment = establishmentRepository.findById(establishmentId); + if (establishment == null) { + LOG.error("Établissement non trouvé avec l'ID : " + establishmentId); + throw new RuntimeException("Établissement non trouvé"); + } + + // Vérifier que l'utilisateur existe + Users user = usersRepository.findById(userId); + if (user == null) { + LOG.error("Utilisateur non trouvé avec l'ID : " + userId); + throw new RuntimeException("Utilisateur non trouvé"); + } + + // Vérifier qu'il n'y a pas déjà une note de cet utilisateur + EstablishmentRating existingRating = ratingRepository.findByEstablishmentIdAndUserId(establishmentId, userId); + if (existingRating != null) { + LOG.error("L'utilisateur " + userId + " a déjà noté l'établissement " + establishmentId); + throw new RuntimeException("Vous avez déjà noté cet établissement. Utilisez la mise à jour pour modifier votre note."); + } + + // Créer la note + EstablishmentRating rating = new EstablishmentRating(establishment, user, requestDTO.getRating()); + rating.setComment(requestDTO.getComment()); + ratingRepository.persist(rating); + + // Mettre à jour les statistiques de l'établissement + updateEstablishmentRatingStats(establishmentId); + + LOG.info("Note soumise avec succès : " + rating.getId()); + return rating; + } + + /** + * Met à jour une note existante. + * + * @param establishmentId L'ID de l'établissement + * @param userId L'ID de l'utilisateur + * @param requestDTO Le DTO contenant la nouvelle note et le commentaire + * @return La note mise à jour + */ + @Transactional + public EstablishmentRating updateRating(UUID establishmentId, UUID userId, EstablishmentRatingRequestDTO requestDTO) { + LOG.info("Mise à jour de la note pour l'établissement " + establishmentId + " par l'utilisateur " + userId); + + // Récupérer la note existante + EstablishmentRating rating = ratingRepository.findByEstablishmentIdAndUserId(establishmentId, userId); + if (rating == null) { + LOG.error("Note non trouvée pour l'établissement " + establishmentId + " et l'utilisateur " + userId); + throw new RuntimeException("Note non trouvée. Utilisez la soumission pour créer une nouvelle note."); + } + + // Mettre à jour la note + rating.updateRating(requestDTO.getRating(), requestDTO.getComment()); + ratingRepository.persist(rating); + + // Mettre à jour les statistiques de l'établissement + updateEstablishmentRatingStats(establishmentId); + + LOG.info("Note mise à jour avec succès : " + rating.getId()); + return rating; + } + + /** + * Récupère la note d'un utilisateur pour un établissement. + * + * @param establishmentId L'ID de l'établissement + * @param userId L'ID de l'utilisateur + * @return La note de l'utilisateur ou null si pas encore noté + */ + public EstablishmentRating getUserRating(UUID establishmentId, UUID userId) { + LOG.info("Récupération de la note de l'utilisateur " + userId + " pour l'établissement " + establishmentId); + return ratingRepository.findByEstablishmentIdAndUserId(establishmentId, userId); + } + + /** + * Récupère les statistiques de notation d'un établissement. + * + * @param establishmentId L'ID de l'établissement + * @return Map contenant averageRating, totalRatings et distribution + */ + public Map getRatingStats(UUID establishmentId) { + LOG.info("Récupération des statistiques de notation pour l'établissement " + establishmentId); + + Double averageRating = ratingRepository.calculateAverageRating(establishmentId); + Long totalRatings = ratingRepository.countByEstablishmentId(establishmentId); + Map distribution = ratingRepository.calculateRatingDistribution(establishmentId); + + return Map.of( + "averageRating", averageRating, + "totalRatingsCount", totalRatings.intValue(), + "ratingDistribution", distribution + ); + } + + /** + * Met à jour les statistiques de notation d'un établissement. + * Cette méthode est appelée après chaque création/modification de note. + * Note: Cette méthode est appelée depuis des méthodes déjà transactionnelles, + * donc pas besoin de l'annotation @Transactional ici. + * + * @param establishmentId L'ID de l'établissement + */ + private void updateEstablishmentRatingStats(UUID establishmentId) { + Establishment establishment = establishmentRepository.findById(establishmentId); + if (establishment == null) { + return; + } + + Double averageRating = ratingRepository.calculateAverageRating(establishmentId); + Long totalRatings = ratingRepository.countByEstablishmentId(establishmentId); + + establishment.setAverageRating(averageRating); + establishment.setTotalRatingsCount(totalRatings.intValue()); + establishmentRepository.persist(establishment); + + LOG.info("Statistiques mises à jour pour l'établissement " + establishmentId + " : moyenne = " + averageRating + ", total = " + totalRatings); + } +} + diff --git a/src/main/java/com/lions/dev/service/EstablishmentService.java b/src/main/java/com/lions/dev/service/EstablishmentService.java new file mode 100644 index 0000000..653acc6 --- /dev/null +++ b/src/main/java/com/lions/dev/service/EstablishmentService.java @@ -0,0 +1,194 @@ +package com.lions.dev.service; + +import com.lions.dev.entity.establishment.Establishment; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.EstablishmentRepository; +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.UUID; +import org.jboss.logging.Logger; + +/** + * Service de gestion des établissements. + * Ce service contient la logique métier pour la création, récupération, + * mise à jour et suppression des établissements. + * Seuls les responsables d'établissement peuvent créer et gérer des établissements. + */ +@ApplicationScoped +public class EstablishmentService { + + @Inject + EstablishmentRepository establishmentRepository; + + @Inject + UsersRepository usersRepository; + + private static final Logger LOG = Logger.getLogger(EstablishmentService.class); + + /** + * Crée un nouvel établissement. + * + * @param establishment L'établissement à créer. + * @param managerId L'ID du responsable de l'établissement. + * @return L'établissement créé. + */ + @Transactional + public Establishment createEstablishment(Establishment establishment, UUID managerId) { + LOG.info("[LOG] Création d'un nouvel établissement : " + establishment.getName()); + + // Vérifier que le manager existe + Users manager = usersRepository.findById(managerId); + if (manager == null) { + LOG.error("[ERROR] Responsable non trouvé avec l'ID : " + managerId); + throw new RuntimeException("Responsable non trouvé avec l'ID fourni"); + } + + // Vérifier que l'utilisateur a le rôle de responsable d'établissement + String role = manager.getRole() != null ? manager.getRole().toUpperCase() : ""; + if (!role.equals("ESTABLISHMENT_MANAGER") && + !role.equals("MANAGER") && + !role.equals("ADMIN")) { + LOG.error("[ERROR] L'utilisateur " + managerId + " n'a pas les droits pour créer un établissement. Rôle : " + role); + throw new RuntimeException("Seuls les responsables d'établissement peuvent créer des établissements"); + } + + establishment.setManager(manager); + establishmentRepository.persist(establishment); + LOG.info("[LOG] Établissement créé avec succès : " + establishment.getName()); + return establishment; + } + + /** + * Récupère tous les établissements. + * + * @return Une liste de tous les établissements. + */ + public List getAllEstablishments() { + LOG.info("[LOG] Récupération de tous les établissements"); + List establishments = establishmentRepository.listAll(); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Récupère un établissement par son ID. + * + * @param id L'ID de l'établissement. + * @return L'établissement trouvé. + */ + public Establishment getEstablishmentById(UUID id) { + LOG.info("[LOG] Récupération de l'établissement avec l'ID : " + id); + Establishment establishment = establishmentRepository.findById(id); + if (establishment == null) { + LOG.warn("[WARN] Établissement non trouvé avec l'ID : " + id); + throw new RuntimeException("Établissement non trouvé avec l'ID : " + id); + } + return establishment; + } + + /** + * Met à jour un établissement existant. + * + * @param id L'ID de l'établissement à mettre à jour. + * @param updatedEstablishment L'établissement avec les nouvelles données. + * @return L'établissement mis à jour. + */ + @Transactional + public Establishment updateEstablishment(UUID id, Establishment updatedEstablishment) { + LOG.info("[LOG] Mise à jour de l'établissement avec l'ID : " + id); + Establishment establishment = establishmentRepository.findById(id); + if (establishment == null) { + LOG.error("[ERROR] Établissement non trouvé avec l'ID : " + id); + throw new RuntimeException("Établissement non trouvé avec l'ID : " + id); + } + + // Mettre à jour les champs + establishment.setName(updatedEstablishment.getName()); + establishment.setType(updatedEstablishment.getType()); + establishment.setAddress(updatedEstablishment.getAddress()); + establishment.setCity(updatedEstablishment.getCity()); + establishment.setPostalCode(updatedEstablishment.getPostalCode()); + establishment.setDescription(updatedEstablishment.getDescription()); + establishment.setPhoneNumber(updatedEstablishment.getPhoneNumber()); + establishment.setEmail(updatedEstablishment.getEmail()); + establishment.setWebsite(updatedEstablishment.getWebsite()); + establishment.setImageUrl(updatedEstablishment.getImageUrl()); + establishment.setRating(updatedEstablishment.getRating()); + establishment.setPriceRange(updatedEstablishment.getPriceRange()); + establishment.setCapacity(updatedEstablishment.getCapacity()); + establishment.setAmenities(updatedEstablishment.getAmenities()); + establishment.setOpeningHours(updatedEstablishment.getOpeningHours()); + establishment.setLatitude(updatedEstablishment.getLatitude()); + establishment.setLongitude(updatedEstablishment.getLongitude()); + + establishmentRepository.persist(establishment); + LOG.info("[LOG] Établissement mis à jour avec succès : " + establishment.getName()); + return establishment; + } + + /** + * Supprime un établissement. + * + * @param id L'ID de l'établissement à supprimer. + */ + @Transactional + public void deleteEstablishment(UUID id) { + LOG.info("[LOG] Suppression de l'établissement avec l'ID : " + id); + Establishment establishment = establishmentRepository.findById(id); + if (establishment == null) { + LOG.error("[ERROR] Établissement non trouvé avec l'ID : " + id); + throw new RuntimeException("Établissement non trouvé avec l'ID : " + id); + } + establishmentRepository.delete(establishment); + LOG.info("[LOG] Établissement supprimé avec succès : " + establishment.getName()); + } + + /** + * Récupère les établissements gérés par un responsable. + * + * @param managerId L'ID du responsable. + * @return Une liste d'établissements gérés par ce responsable. + */ + public List getEstablishmentsByManager(UUID managerId) { + LOG.info("[LOG] Récupération des établissements du responsable : " + managerId); + List establishments = establishmentRepository.findByManagerId(managerId); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Recherche des établissements par nom ou ville. + * + * @param query Le terme de recherche. + * @return Une liste d'établissements correspondant à la recherche. + */ + public List searchEstablishments(String query) { + LOG.info("[LOG] Recherche d'établissements avec la requête : " + query); + List establishments = establishmentRepository.searchByNameOrCity(query); + LOG.info("[LOG] Nombre d'établissements trouvés : " + establishments.size()); + return establishments; + } + + /** + * Filtre les établissements par type, fourchette de prix et/ou ville. + * + * @param type Le type d'établissement (optionnel). + * @param priceRange La fourchette de prix (optionnel). + * @param city La ville (optionnel). + * @return Une liste d'établissements correspondant aux filtres. + */ + public List filterEstablishments(String type, String priceRange, String city) { + LOG.info("[LOG] Filtrage des établissements : type=" + type + ", priceRange=" + priceRange + ", city=" + city); + List allEstablishments = establishmentRepository.listAll(); + + return allEstablishments.stream() + .filter(e -> type == null || e.getType().equalsIgnoreCase(type)) + .filter(e -> priceRange == null || (e.getPriceRange() != null && e.getPriceRange().equalsIgnoreCase(priceRange))) + .filter(e -> city == null || e.getCity().equalsIgnoreCase(city)) + .toList(); + } +} +