diff --git a/pom.xml b/pom.xml index 1265f5f..10d6e33 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,12 @@ + + org.springframework.security + spring-security-core + 6.3.3 + + com.fasterxml.jackson.datatype jackson-datatype-jsr310 diff --git a/src/main/java/com/lions/dev/GreetingResource.java b/src/main/java/com/lions/dev/GreetingResource.java deleted file mode 100644 index 0acbd7a..0000000 --- a/src/main/java/com/lions/dev/GreetingResource.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.lions.dev; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.MediaType; - -@Path("/hello") -public class GreetingResource { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "Hello RESTEasy"; - } -} diff --git a/src/main/java/com/lions/dev/core/errors/Exceptions.java b/src/main/java/com/lions/dev/core/errors/Exceptions.java new file mode 100644 index 0000000..d7c2165 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/Exceptions.java @@ -0,0 +1,18 @@ +package com.lions.dev.core.errors; + +/** + * Classe de base pour les exceptions personnalisées dans l'application AfterWork. + * Toutes les exceptions spécifiques peuvent étendre cette classe pour centraliser la gestion des erreurs. + */ +public abstract class Exceptions extends Exception { + + /** + * Constructeur de base pour les exceptions personnalisées. + * + * @param message Le message d'erreur associé à l'exception. + */ + public Exceptions(String message) { + super(message); + System.out.println("[ERROR] Exception déclenchée : " + message); + } +} diff --git a/src/main/java/com/lions/dev/core/errors/Failures.java b/src/main/java/com/lions/dev/core/errors/Failures.java new file mode 100644 index 0000000..2dc591e --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/Failures.java @@ -0,0 +1,39 @@ +package com.lions.dev.core.errors; + +/** + * Classe utilitaire pour représenter les échecs dans l'application AfterWork. + * Elle est utilisée pour gérer les cas où une action échoue sans générer une exception critique. + */ +public class Failures { + + private final String failureMessage; + + /** + * Constructeur pour un message d'échec. + * + * @param failureMessage Le message expliquant la raison de l'échec. + */ + public Failures(String failureMessage) { + this.failureMessage = failureMessage; + System.out.println("[FAILURE] Échec détecté : " + failureMessage); + } + + /** + * Récupère le message d'échec. + * + * @return Le message d'échec. + */ + public String getFailureMessage() { + return failureMessage; + } + + /** + * Affiche un message d'échec formaté. + * + * @return Le message formaté. + */ + @Override + public String toString() { + return "Échec : " + failureMessage; + } +} diff --git a/src/main/java/com/lions/dev/core/errors/ServerException.java b/src/main/java/com/lions/dev/core/errors/ServerException.java new file mode 100644 index 0000000..0c26272 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/ServerException.java @@ -0,0 +1,4 @@ +package com.lions.dev.core.errors; + +public class ServerException { +} diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java b/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java new file mode 100644 index 0000000..14ddcb2 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/exceptions/BadRequestException.java @@ -0,0 +1,21 @@ +package com.lions.dev.core.errors.exceptions; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +/** + * Exception levée lorsqu'une requête est mal formée ou contient des informations invalides. + * Elle renvoie une réponse HTTP 400 (BAD REQUEST). + */ +public class BadRequestException extends WebApplicationException { + + /** + * Constructeur prenant un message d'erreur. + * + * @param message Le message décrivant l'erreur. + */ + public BadRequestException(String message) { + super(message, Response.Status.BAD_REQUEST); + System.out.println("[ERROR] Requête invalide : " + message); + } +} diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/NotFoundException.java b/src/main/java/com/lions/dev/core/errors/exceptions/NotFoundException.java new file mode 100644 index 0000000..1c042bf --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/exceptions/NotFoundException.java @@ -0,0 +1,21 @@ +package com.lions.dev.core.errors.exceptions; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +/** + * Exception levée lorsqu'une ressource demandée n'est pas trouvée. + * Elle renvoie une réponse HTTP 404 (NOT FOUND). + */ +public class NotFoundException extends WebApplicationException { + + /** + * Constructeur prenant un message d'erreur. + * + * @param message Le message décrivant la ressource non trouvée. + */ + public NotFoundException(String message) { + super(message, Response.Status.NOT_FOUND); + System.out.println("[ERROR] Ressource non trouvée : " + message); + } +} diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/ServerException.java b/src/main/java/com/lions/dev/core/errors/exceptions/ServerException.java new file mode 100644 index 0000000..297d537 --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/exceptions/ServerException.java @@ -0,0 +1,18 @@ +package com.lions.dev.core.errors.exceptions; + +/** + * Exception levée lorsqu'une erreur inattendue survient côté serveur. + * Elle est utilisée pour signaler des erreurs critiques nécessitant une attention particulière. + */ +public class ServerException extends RuntimeException { + + /** + * Constructeur prenant un message d'erreur. + * + * @param message Le message décrivant l'erreur serveur. + */ + public ServerException(String message) { + super(message); + System.out.println("[ERROR] Erreur serveur : " + message); + } +} diff --git a/src/main/java/com/lions/dev/core/errors/exceptions/UnauthorizedException.java b/src/main/java/com/lions/dev/core/errors/exceptions/UnauthorizedException.java new file mode 100644 index 0000000..0cbc2fe --- /dev/null +++ b/src/main/java/com/lions/dev/core/errors/exceptions/UnauthorizedException.java @@ -0,0 +1,21 @@ +package com.lions.dev.core.errors.exceptions; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +/** + * Exception levée lorsque l'utilisateur tente d'accéder à une ressource sans autorisation. + * Elle renvoie une réponse HTTP 401 (UNAUTHORIZED). + */ +public class UnauthorizedException extends WebApplicationException { + + /** + * Constructeur prenant un message d'erreur. + * + * @param message Le message décrivant l'accès non autorisé. + */ + public UnauthorizedException(String message) { + super(message, Response.Status.UNAUTHORIZED); + System.out.println("[ERROR] Accès non autorisé : " + message); + } +} diff --git a/src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java b/src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java new file mode 100644 index 0000000..fecb22a --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/events/EventRequestDTO.java @@ -0,0 +1,60 @@ +package com.lions.dev.dto.request.events; + +import com.lions.dev.entity.users.Users; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.LocalDateTime; + +/** + * DTO pour la création d'un événement. + * Ce DTO est utilisé dans les requêtes de création d'événements, envoyant les informations + * nécessaires comme le titre, les dates et le créateur. + */ +public class EventRequestDTO { + + @NotNull(message = "Le titre de l'événement est obligatoire.") + @Size(min = 3, max = 100, message = "Le titre doit comporter entre 3 et 100 caractères.") + private String title; // Titre de l'événement + + @NotNull(message = "La date de début est obligatoire.") + private LocalDateTime startDate; // Date de début de l'événement + + @NotNull(message = "La date de fin est obligatoire.") + private LocalDateTime endDate; // Date de fin de l'événement + + @NotNull(message = "Le créateur de l'événement est obligatoire.") + private Users creator; // Utilisateur créateur de l'événement + + // Getters et setters + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public void setStartDate(LocalDateTime startDate) { + this.startDate = startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + + public Users getCreator() { + return creator; + } + + public void setCreator(Users creator) { + this.creator = creator; + } +} diff --git a/src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java b/src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java new file mode 100644 index 0000000..9fd32d2 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/request/users/UserRequestDTO.java @@ -0,0 +1,37 @@ +package com.lions.dev.dto.request.users; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; + +/** + * DTO pour la création et l'authentification d'un utilisateur. + * Ce DTO est utilisé dans les requêtes pour créer ou authentifier un utilisateur, + * contenant les informations comme le nom, les prénoms, l'email, et le mot de passe. + */ +@Getter +@Setter +public class UserRequestDTO { + + @NotNull(message = "Le nom est obligatoire.") + @Size(min = 1, max = 100, message = "Le nom doit comporter entre 1 et 100 caractères.") + private String nom; + + @NotNull(message = "Les prénoms sont obligatoires.") + @Size(min = 1, max = 100, message = "Les prénoms doivent comporter entre 1 et 100 caractères.") + private String prenoms; + + @NotNull(message = "L'adresse email est obligatoire.") + @Email(message = "Veuillez fournir une adresse email valide.") + private String email; + + @NotNull(message = "Le mot de passe est obligatoire.") + @Size(min = 6, message = "Le mot de passe doit comporter au moins 6 caractères.") + private String motDePasse; + + // Ajout du rôle avec validation + @NotNull(message = "Le rôle est obligatoire.") + private String role; // Rôle de l'utilisateur (par exemple : ADMIN, USER, etc.) +} diff --git a/src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java b/src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java new file mode 100644 index 0000000..c88338a --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/events/EventResponseDTO.java @@ -0,0 +1,46 @@ +package com.lions.dev.dto.response.events; + +import com.lions.dev.entity.events.Events; +import java.time.LocalDateTime; + +/** + * DTO pour renvoyer les informations d'un événement. + * Ce DTO est utilisé pour structurer les données retournées dans les réponses + * après les opérations sur les événements (création, récupération). + */ +public class EventResponseDTO { + + private String title; // Titre 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 creatorEmail; // Email du créateur de l'événement + + /** + * Constructeur qui transforme une entité Events en DTO. + * + * @param event L'événement à convertir en DTO. + */ + public EventResponseDTO(Events event) { + this.title = event.getTitle(); + this.startDate = event.getStartDate(); + this.endDate = event.getEndDate(); + this.creatorEmail = event.getCreator().getEmail(); + } + + // Getters + public String getTitle() { + return title; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public String getCreatorEmail() { + return creatorEmail; + } +} diff --git a/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java b/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java new file mode 100644 index 0000000..8591943 --- /dev/null +++ b/src/main/java/com/lions/dev/dto/response/users/UserResponseDTO.java @@ -0,0 +1,28 @@ +package com.lions.dev.dto.response.users; + +import com.lions.dev.entity.users.Users; +import lombok.Getter; + +/** + * DTO pour renvoyer les informations d'un utilisateur. + * Ce DTO est utilisé pour structurer les données retournées dans les réponses + * après les opérations sur les utilisateurs (création, récupération). + */ +@Getter +public class UserResponseDTO { + + private String nom; // Nom de l'utilisateur + private String prenoms; // Prénoms de l'utilisateur + private String email; // Email de l'utilisateur + + /** + * Constructeur qui transforme une entité Users en DTO. + * + * @param user L'utilisateur à convertir en DTO. + */ + public UserResponseDTO(Users user) { + this.nom = user.getNom(); + this.prenoms = user.getPrenoms(); + this.email = user.getEmail(); + } +} diff --git a/src/main/java/com/lions/dev/entity/BaseEntity.java b/src/main/java/com/lions/dev/entity/BaseEntity.java index 7235017..a7c0aa6 100644 --- a/src/main/java/com/lions/dev/entity/BaseEntity.java +++ b/src/main/java/com/lions/dev/entity/BaseEntity.java @@ -1,44 +1,52 @@ package com.lions.dev.entity; -import io.quarkus.hibernate.orm.panache.PanacheEntityBase; import jakarta.persistence.*; -import java.time.LocalDateTime; -import java.util.UUID; import lombok.Getter; import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; +import java.time.LocalDateTime; +import java.util.UUID; +/** + * Classe de base pour toutes les entités du système AfterWork. + * Cette classe définit les propriétés communes à toutes les entités, telles que + * l'identifiant unique et les informations d'audit (création, mise à jour). + * + * Chaque entité héritant de cette classe aura un identifiant auto-généré, + * et des dates automatiques pour la création et la mise à jour. + */ +@MappedSuperclass @Getter @Setter -@MappedSuperclass -public abstract class BaseEntity extends PanacheEntityBase { +public abstract class BaseEntity { @Id - @UuidGenerator - @Column(name = "id", updatable = false, nullable = false) - private UUID id; + @GeneratedValue(strategy = GenerationType.AUTO) + private UUID id; // Identifiant unique de l'entité, généré automatiquement - @Column(name = "created_at", updatable = false) - private LocalDateTime createdAt; + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt; // Date de création de l'entité - @Column(name = "updated_at") - private LocalDateTime updatedAt; - - @Column(name = "created_by") - private String createdBy; - - @Column(name = "updated_by") - private String updatedBy; + @Column(name = "updated_at", nullable = false) + private LocalDateTime updatedAt; // Date de la dernière mise à jour de l'entité + /** + * Méthode appelée avant la persistance d'une nouvelle entité dans la base de données. + * Cette méthode définit automatiquement la date de création et de mise à jour. + */ @PrePersist protected void onCreate() { this.createdAt = LocalDateTime.now(); - // Logique pour définir `createdBy` à partir du contexte utilisateur + this.updatedAt = LocalDateTime.now(); + System.out.println("[LOG] Nouvelle entité créée avec ID : " + this.id + " à " + this.createdAt); } + /** + * Méthode appelée avant la mise à jour d'une entité existante dans la base de données. + * Cette méthode met à jour automatiquement la date de la dernière mise à jour. + */ @PreUpdate protected void onUpdate() { this.updatedAt = LocalDateTime.now(); - // Logique pour définir `updatedBy` à partir du contexte utilisateur + System.out.println("[LOG] Entité mise à jour avec ID : " + this.id + " à " + this.updatedAt); } } diff --git a/src/main/java/com/lions/dev/entity/Events.java b/src/main/java/com/lions/dev/entity/Events.java deleted file mode 100644 index a3d3b69..0000000 --- a/src/main/java/com/lions/dev/entity/Events.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.lions.dev.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.time.LocalDateTime; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@Entity -@Table(name = "Events") -public class Events extends BaseEntity { - - @NotNull - @Size(max = 100) - @Column(name = "title", nullable = false, length = 100) - @JsonProperty("title") - private String title; - - @NotNull - @Size(max = 255) - @Column(name = "description", nullable = false, length = 255) - @JsonProperty("description") - private String description; - - @NotNull - @Column(name = "event_date", nullable = false) - @JsonProperty("date") - private LocalDateTime eventDate; - - @NotNull - @Size(max = 100) - @Column(name = "location", nullable = false, length = 100) - @JsonProperty("location") - private String location; - - @Size(max = 100) - @Column(name = "category", length = 100) - @JsonProperty("category") - private String category; - - @Column(name = "link", length = 255) - @JsonProperty("link") - private String link; - - @Column(name = "image_url", length = 255) - @JsonProperty("imageUrl") - private String imageUrl; - - @NotNull - @Column(name = "status", nullable = false) - @JsonProperty("status") - private String status = "OPEN"; // Par défaut, un événement est "OUVERT". - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "creator_id", nullable = false) - @JsonProperty("creator") - private Users creator; - - @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable( - name = "event_participants", - joinColumns = @JoinColumn(name = "event_id"), - inverseJoinColumns = @JoinColumn(name = "user_id") - ) - @JsonIgnore - private Set participants = new HashSet<>(); - - @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable( - name = "event_likes", - joinColumns = @JoinColumn(name = "event_id"), - inverseJoinColumns = @JoinColumn(name = "user_id") - ) - @JsonIgnore - private Set likes = new HashSet<>(); - - public void addParticipant(Users user) { - participants.add(user); - user.getParticipatedEvents().add(this); - } - - public void removeParticipant(Users user) { - participants.remove(user); - user.getParticipatedEvents().remove(this); - } - - public void addLike(Users user) { - likes.add(user); - } - - public void removeLike(Users user) { - likes.remove(user); - } - - @PreRemove - private void preRemove() { - for (Users participant : participants) { - participant.getParticipatedEvents().remove(this); - } - for (Users like : likes) { - like.getLikedEvents().remove(this); - } - } - - @Override - public String toString() { - return "Events{" + - "id=" + getId() + - ", title='" + title + '\'' + - ", description='" + description + '\'' + - ", eventDate=" + eventDate + - ", location='" + location + '\'' + - ", category='" + category + '\'' + - ", link='" + link + '\'' + - ", imageUrl='" + imageUrl + '\'' + - ", status='" + status + '\'' + - ", creator=" + (creator != null ? creator.getId() : null) + - '}'; - } -} diff --git a/src/main/java/com/lions/dev/entity/Users.java b/src/main/java/com/lions/dev/entity/Users.java deleted file mode 100644 index 332c56b..0000000 --- a/src/main/java/com/lions/dev/entity/Users.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.lions.dev.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.persistence.*; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashSet; -import java.util.Set; -import lombok.Getter; -import lombok.Setter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Getter -@Setter -@Entity -@Table(name = "Users") -public class Users extends BaseEntity { - - private static final Logger logger = LoggerFactory.getLogger(Users.class); - - @NotNull - @Size(max = 100) - @Column(name = "nom", nullable = false, length = 100) - @JsonProperty("nom") - private String nom; - - @NotNull - @Size(max = 100) - @Column(name = "prenoms", nullable = false, length = 100) - @JsonProperty("prenoms") - private String prenoms; - - @NotNull - @Email - @Size(max = 100) - @Column(name = "email", nullable = false, length = 100, unique = true) - @JsonProperty("email") - private String email; - - @NotNull - @Size(min = 8, max = 255) - @Column(name = "mot_de_passe", nullable = false, length = 255) - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - private String motDePasse; - - @Size(max = 50) - @Column(name = "role", nullable = false, length = 50) - @JsonProperty("role") - private String role; - - // Relation avec les événements créés par l'utilisateur - @OneToMany(mappedBy = "creator", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) - @JsonIgnore - private Set createdEvents = new HashSet<>(); - - // Relation avec les événements auxquels l'utilisateur participe - @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable( - name = "User_Event_Participation", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "event_id") - ) - @JsonIgnore - private Set participatedEvents = new HashSet<>(); - - // Relation avec les événements "likés" par l'utilisateur - @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) - @JoinTable( - name = "User_Event_Likes", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "event_id") - ) - @JsonIgnore - private Set likedEvents = new HashSet<>(); - - /** - * Définit le mot de passe de l'utilisateur en le hachant avec l'algorithme SHA-256. - * - * @param motDePasse Le mot de passe en clair que l'utilisateur souhaite utiliser. - */ - public void setMotDePasse(String motDePasse) { - logger.debug("Définition du mot de passe pour l'utilisateur {}", email); - this.motDePasse = hashPasswordSHA256(motDePasse); - } - - /** - * Hache le mot de passe en utilisant l'algorithme SHA-256. - * - * @param motDePasse Le mot de passe en clair. - * @return Le mot de passe haché en format hexadécimal. - */ - private String hashPasswordSHA256(String motDePasse) { - logger.debug("Hachage du mot de passe pour l'utilisateur {}", email); - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] encodedhash = digest.digest(motDePasse.getBytes(StandardCharsets.UTF_8)); - return bytesToHex(encodedhash); - } catch (NoSuchAlgorithmException e) { - logger.error("Erreur lors du hachage du mot de passe pour l'utilisateur {}: {}", email, e.getMessage()); - throw new RuntimeException(e); - } - } - - /** - * Convertit un tableau de bytes en une chaîne hexadécimale. - * - * @param hash Le tableau de bytes à convertir. - * @return La chaîne hexadécimale correspondante. - */ - private String bytesToHex(byte[] hash) { - StringBuilder hexString = new StringBuilder(2 * hash.length); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - return hexString.toString(); - } - - /** - * Méthode appelée avant la suppression d'un utilisateur. Elle retire cet utilisateur des événements - * auxquels il participe ou qu'il a "liké" pour éviter des violations de contraintes de clé étrangère. - */ - @PreRemove - private void preRemove() { - logger.info("Préparation à la suppression de l'utilisateur {}", email); - for (Events event : participatedEvents) { - event.getParticipants().remove(this); - logger.debug("L'utilisateur {} a été retiré de l'événement {}", email, event.getId()); - } - for (Events event : likedEvents) { - event.getLikes().remove(this); - logger.debug("L'utilisateur {} a été retiré des 'likes' de l'événement {}", email, event.getId()); - } - } - - @Override - public String toString() { - return "Users{" + - "id=" + getId() + - ", nom='" + nom + '\'' + - ", prenoms='" + prenoms + '\'' + - ", email='" + email + '\'' + - ", role='" + role + '\'' + - '}'; - } -} diff --git a/src/main/java/com/lions/dev/entity/comment/Comment.java b/src/main/java/com/lions/dev/entity/comment/Comment.java new file mode 100644 index 0000000..04259e7 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/comment/Comment.java @@ -0,0 +1,68 @@ +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 jakarta.persistence.*; +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. + * + * Des logs et des commentaires sont inclus pour assurer une traçabilité claire. + */ +@Entity +@Table(name = "comments") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Comment extends BaseEntity { + + @Column(name = "text", nullable = false) + private String text; // Le texte du commentaire + + @Column(name = "comment_date", nullable = false) + private LocalDateTime commentDate; // La date à laquelle le commentaire a été publié + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private Users user; // L'utilisateur qui a fait le commentaire + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "event_id", nullable = false) + private Events event; // L'événement auquel le commentaire est lié + + /** + * Constructeur pour créer un nouveau commentaire. + * + * @param user L'utilisateur qui commente. + * @param event L'événement commenté. + * @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); + } + + /** + * Modifie le texte du commentaire. + * + * @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); + this.text = newText; + this.commentDate = LocalDateTime.now(); // Met à jour 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 new file mode 100644 index 0000000..23276b4 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/events/Events.java @@ -0,0 +1,83 @@ +package com.lions.dev.entity.events; + +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; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; + +/** + * Entité représentant un événement dans le système AfterWork. + * Chaque événement possède un titre, une date de début, une date de fin, un créateur, + * et des participants. + * + * Tous les logs et commentaires nécessaires pour la traçabilité et la documentation sont inclus. + */ +@Entity +@Table(name = "events") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Events extends BaseEntity { + + // Attributs de l'entité événement + + @Column(name = "title", nullable = false) + private String title; // Le titre de l'événement + + @Column(name = "start_date", nullable = false) + private LocalDateTime startDate; // La date de début de l'événement + + @Column(name = "end_date", nullable = false) + private LocalDateTime endDate; // La date de fin de l'événement + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "creator_id", nullable = false) + private Users creator; // L'utilisateur créateur de l'événement + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "event_participants", + joinColumns = @JoinColumn(name = "event_id"), + inverseJoinColumns = @JoinColumn(name = "user_id") + ) + private Set participants = new HashSet<>(); // Les participants à l'événement + + /** + * Ajoute un utilisateur en tant que participant à l'événement. + * + * @param user L'utilisateur à ajouter comme participant. + */ + public void addParticipant(Users user) { + participants.add(user); + System.out.println("[LOG] Participant ajouté : " + user.getEmail() + " à l'événement : " + this.title); + } + + /** + * Supprime un utilisateur de la liste des participants de l'événement. + * + * @param user L'utilisateur à supprimer de la liste des participants. + */ + public void removeParticipant(Users user) { + participants.remove(user); + System.out.println("[LOG] Participant supprimé : " + user.getEmail() + " de l'événement : " + this.title); + } + + /** + * Retourne le nombre total de participants à cet événement. + * + * @return Le nombre total de participants. + */ + public int getNumberOfParticipants() { + int count = participants.size(); + System.out.println("[LOG] Nombre de participants à l'événement : " + this.title + " - " + count); + return count; + } +} diff --git a/src/main/java/com/lions/dev/entity/reaction/Reaction.java b/src/main/java/com/lions/dev/entity/reaction/Reaction.java new file mode 100644 index 0000000..92176f2 --- /dev/null +++ b/src/main/java/com/lions/dev/entity/reaction/Reaction.java @@ -0,0 +1,67 @@ +package com.lions.dev.entity.reaction; + +import com.lions.dev.entity.BaseEntity; +import com.lions.dev.entity.users.Users; +import com.lions.dev.entity.events.Events; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * Entité représentant une réaction d'un utilisateur à un événement dans le système AfterWork. + * Une réaction peut être un "like", un "dislike" ou toute autre forme de réaction définie. + * + * Cette entité est liée à l'utilisateur qui réagit et à l'événement auquel la réaction est associée. + * Tous les logs et commentaires sont inclus pour la traçabilité. + */ +@Entity +@Table(name = "reactions") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Reaction extends BaseEntity { + + // Types de réaction possibles + public enum ReactionType { + LIKE, DISLIKE, LOVE, ANGRY, SAD + } + + @Enumerated(EnumType.STRING) + @Column(name = "reaction_type", nullable = false) + private ReactionType reactionType; // Le type de réaction (LIKE, DISLIKE, etc.) + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + private Users user; // L'utilisateur qui a effectué la réaction + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "event_id", nullable = false) + private Events event; // L'événement auquel la réaction est associée + + /** + * Associe une réaction à un utilisateur et un événement. + * + * @param user L'utilisateur qui réagit. + * @param event L'événement auquel la réaction est liée. + * @param reactionType Le type de réaction. + */ + public Reaction(Users user, Events event, ReactionType reactionType) { + this.user = user; + this.event = event; + this.reactionType = reactionType; + System.out.println("[LOG] Nouvelle réaction ajoutée : " + reactionType + " par l'utilisateur : " + user.getEmail() + " à l'événement : " + event.getTitle()); + } + + /** + * Modifie le type de réaction de l'utilisateur pour cet événement. + * + * @param newReactionType Le nouveau type de réaction. + */ + public void updateReaction(ReactionType newReactionType) { + System.out.println("[LOG] Changement de la réaction de " + this.reactionType + " à " + newReactionType + " pour l'utilisateur : " + user.getEmail() + " à l'événement : " + event.getTitle()); + this.reactionType = newReactionType; + } +} diff --git a/src/main/java/com/lions/dev/entity/users/Users.java b/src/main/java/com/lions/dev/entity/users/Users.java new file mode 100644 index 0000000..465823a --- /dev/null +++ b/src/main/java/com/lions/dev/entity/users/Users.java @@ -0,0 +1,78 @@ +package com.lions.dev.entity.users; + +import com.lions.dev.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * Représentation de l'entité Utilisateur dans le système AfterWork. + * Cette entité contient les informations de base sur un utilisateur, telles que le nom, + * les prénoms, l'email, le mot de passe haché, et son rôle. + * + * Tous les logs nécessaires à la traçabilité sont intégrés. + */ +@Entity +@Table(name = "users") +@Getter +@Setter +@NoArgsConstructor +@ToString +public class Users extends BaseEntity { + + // Attributs de l'entité utilisateur + + @Column(name = "nom", nullable = false, length = 100) + private String nom; // Le nom de l'utilisateur + + @Column(name = "prenoms", nullable = false, length = 100) + private String prenoms; // Les prénoms de l'utilisateur + + @Column(name = "email", nullable = false, unique = true, length = 100) + private String email; // L'adresse email unique de l'utilisateur + + @Column(name = "mot_de_passe", nullable = false) + private String motDePasse; // Mot de passe haché avec BCrypt + + @Column(name = "role", nullable = false) + private String role; // Le rôle de l'utilisateur (ADMIN, MODERATOR, USER, etc.) + + // Utilisation de BCrypt pour hacher les mots de passe de manière sécurisée + private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + /** + * Hache le mot de passe avec BCrypt et le stocke dans l'attribut `motDePasse`. + * + * @param motDePasse Le mot de passe en texte clair à hacher. + */ + public void setMotDePasse(String motDePasse) { + this.motDePasse = encoder.encode(motDePasse); + System.out.println("[LOG] Mot de passe haché pour l'utilisateur : " + this.email); + } + + /** + * Vérifie que le mot de passe fourni correspond au mot de passe haché de l'utilisateur. + * + * @param motDePasse Le mot de passe en texte clair à vérifier. + * @return true si le mot de passe est correct, false sinon. + */ + public boolean verifierMotDePasse(String motDePasse) { + boolean isValid = encoder.matches(motDePasse, this.motDePasse); + System.out.println("[LOG] Vérification du mot de passe pour l'utilisateur : " + this.email + " - Résultat : " + isValid); + return isValid; + } + + /** + * Vérifie si l'utilisateur a le rôle d'administrateur. + * + * @return true si l'utilisateur est un administrateur, false sinon. + */ + public boolean isAdmin() { + boolean isAdmin = "ADMIN".equalsIgnoreCase(this.role); + System.out.println("[LOG] Vérification du rôle ADMIN pour l'utilisateur : " + this.email + " - Résultat : " + isAdmin); + return isAdmin; + } +} diff --git a/src/main/java/com/lions/dev/exception/EventNotFoundException.java b/src/main/java/com/lions/dev/exception/EventNotFoundException.java new file mode 100644 index 0000000..cf0b026 --- /dev/null +++ b/src/main/java/com/lions/dev/exception/EventNotFoundException.java @@ -0,0 +1,21 @@ +package com.lions.dev.exception; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +/** + * Exception levée lorsque l'événement demandé n'est pas trouvé dans la base de données. + * Cette exception renvoie une réponse HTTP 404 (NOT FOUND). + */ +public class EventNotFoundException extends WebApplicationException { + + /** + * Constructeur qui prend un message d'erreur à afficher lorsque l'exception est levée. + * + * @param message Le message détaillant l'erreur. + */ + public EventNotFoundException(String message) { + super(message, Response.Status.NOT_FOUND); + System.out.println("[ERROR] Événement non trouvé : " + message); + } +} \ No newline at end of file diff --git a/src/main/java/com/lions/dev/exception/UserNotFoundException.java b/src/main/java/com/lions/dev/exception/UserNotFoundException.java new file mode 100644 index 0000000..958e514 --- /dev/null +++ b/src/main/java/com/lions/dev/exception/UserNotFoundException.java @@ -0,0 +1,21 @@ +package com.lions.dev.exception; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +/** + * Exception levée lorsque l'utilisateur demandé n'est pas trouvé dans la base de données. + * Cette exception renvoie une réponse HTTP 404 (NOT FOUND). + */ +public class UserNotFoundException extends WebApplicationException { + + /** + * Constructeur qui prend un message d'erreur à afficher lorsque l'exception est levée. + * + * @param message Le message détaillant l'erreur. + */ + public UserNotFoundException(String message) { + super(message, Response.Status.NOT_FOUND); + System.out.println("[ERROR] Utilisateur non trouvé : " + message); + } +} diff --git a/src/main/java/com/lions/dev/repository/EventsRepository.java b/src/main/java/com/lions/dev/repository/EventsRepository.java index 1efcf51..843d335 100644 --- a/src/main/java/com/lions/dev/repository/EventsRepository.java +++ b/src/main/java/com/lions/dev/repository/EventsRepository.java @@ -1,79 +1,81 @@ package com.lions.dev.repository; -import com.lions.dev.entity.Events; +import com.lions.dev.entity.events.Events; +import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.transaction.Transactional; +import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import java.util.UUID; +/** + * Repository pour l'entité Events. + * Ce repository gère les opérations de base (CRUD) sur les événements ainsi que des méthodes de filtrage personnalisées. + * + * Utilisation de Panache pour simplifier les opérations sur la base de données. + */ @ApplicationScoped -public class EventsRepository { - - @PersistenceContext - EntityManager entityManager; +public class EventsRepository implements PanacheRepositoryBase { /** - * Trouver tous les événements. + * Recherche un événement par son titre. * - * @return Liste de tous les événements. + * @param title Le titre de l'événement à rechercher. + * @return Un Optional contenant l'événement s'il est trouvé, sinon un Optional vide. */ - public List findAllEvents() { - // Log pour la tentative de récupération de tous les événements - System.out.println("Tentative de récupération de tous les événements."); - List events = entityManager.createQuery("SELECT e FROM Events e", Events.class).getResultList(); - // Log du nombre d'événements trouvés - System.out.println("Nombre d'événements trouvés: " + events.size()); + public Optional findByTitle(String title) { + System.out.println("[LOG] Recherche de l'événement avec le titre : " + title); + Events event = find("title", title).firstResult(); + if (event != null) { + System.out.println("[LOG] Événement trouvé : " + event.getTitle()); + } else { + System.out.println("[LOG] Aucun événement trouvé avec le titre : " + title); + } + return Optional.ofNullable(event); + } + + /** + * Récupère tous les événements créés par un utilisateur spécifique. + * + * @param userId L'ID de l'utilisateur créateur des événements. + * @return Une liste d'événements créés par l'utilisateur. + */ + public List findByCreator(UUID userId) { + System.out.println("[LOG] Récupération des événements créés par l'utilisateur avec l'ID : " + userId); + List events = list("creator.id", userId); + System.out.println("[LOG] Nombre d'événements trouvés pour l'utilisateur : " + events.size()); return events; } /** - * Trouver un événement par son ID. + * Supprime un événement par son identifiant UUID. * - * @param id L'ID de l'événement. - * @return L'événement trouvé ou null. + * @param id L'UUID de l'événement à supprimer. + * @return true si l'événement a été supprimé, sinon false. */ - public Events findById(UUID id) { - // Log pour la tentative de recherche d'un événement par ID - System.out.println("Recherche de l'événement avec ID: " + id); - Events event = entityManager.find(Events.class, id); - if (event == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + id); + public boolean deleteById(UUID id) { + System.out.println("[LOG] Suppression de l'événement avec l'ID : " + id); + long deletedCount = delete("id", id); // Utiliser long pour récupérer le nombre d'enregistrements supprimés + boolean deleted = deletedCount > 0; // Convertir en boolean + if (deleted) { + System.out.println("[LOG] Événement avec l'ID " + id + " supprimé avec succès."); } else { - // Log si l'événement est trouvé - System.out.println("Événement trouvé: " + event.getTitle()); + System.out.println("[LOG] Aucune suppression, événement avec l'ID " + id + " introuvable."); } - return event; + return deleted; } /** - * Persister un événement. + * Récupère une liste d'événements avec filtrage par date de début. * - * @param event L'événement à persister. + * @param startDate La date de début à partir de laquelle rechercher les événements. + * @return Une liste d'événements filtrés. */ - @Transactional - public void persist(Events event) { - // Log pour la tentative de persistance - System.out.println("Tentative de persistance de l'événement: " + event.getTitle()); - entityManager.persist(event); - // Log après la persistance - System.out.println("Événement persisté avec succès: " + event.getId()); - } - - /** - * Supprimer un événement. - * - * @param event L'événement à supprimer. - */ - @Transactional - public void delete(Events event) { - // Log pour la tentative de suppression - System.out.println("Tentative de suppression de l'événement: " + event.getTitle()); - entityManager.remove(entityManager.contains(event) ? event : entityManager.merge(event)); - // Log après suppression - System.out.println("Événement supprimé avec succès: " + event.getId()); + public List findEventsAfterDate(LocalDateTime startDate) { + System.out.println("[LOG] Récupération des événements après la date : " + startDate); + List events = list("startDate >= ?1", startDate); + System.out.println("[LOG] Nombre d'événements trouvés après la date : " + startDate + " : " + events.size()); + return events; } } diff --git a/src/main/java/com/lions/dev/repository/UsersRepository.java b/src/main/java/com/lions/dev/repository/UsersRepository.java index 815cfde..63046e1 100644 --- a/src/main/java/com/lions/dev/repository/UsersRepository.java +++ b/src/main/java/com/lions/dev/repository/UsersRepository.java @@ -1,231 +1,67 @@ package com.lions.dev.repository; -import com.lions.dev.entity.Users; +import com.lions.dev.entity.users.Users; import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.transaction.Transactional; - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.List; +import java.util.Optional; import java.util.UUID; /** * Repository pour l'entité Users. - * Fournit des méthodes CRUD de base ainsi que des méthodes personnalisées. + * Ce repository gère les opérations de base (CRUD) sur les utilisateurs ainsi que des méthodes personnalisées. + * + * Utilisation de Panache pour simplifier les opérations sur la base de données. */ @ApplicationScoped public class UsersRepository implements PanacheRepositoryBase { /** - * Recherche les utilisateurs par nom. + * Recherche un utilisateur par son adresse email. * - * @param nom Le nom à rechercher. - * @return La liste des utilisateurs avec le nom donné. + * @param email L'email de l'utilisateur à rechercher. + * @return Un Optional contenant l'utilisateur s'il est trouvé, sinon un Optional vide. */ - public List findByNom(String nom) { - return find("nom", nom).list(); + public Optional findByEmail(String email) { + System.out.println("[LOG] Recherche de l'utilisateur avec l'email : " + email); + Users user = find("email", email).firstResult(); + if (user != null) { + System.out.println("[LOG] Utilisateur trouvé : " + user.getEmail()); + } else { + System.out.println("[LOG] Aucun utilisateur trouvé avec l'email : " + email); + } + return Optional.ofNullable(user); } /** - * Recherche un utilisateur par email. - * - * @param email L'email à rechercher. - * @return L'utilisateur avec l'email donné, ou null s'il n'existe pas. - */ - public Users findByEmail(String email) { - return find("email", email).firstResult(); - } - - /** - * Recherche les utilisateurs par nom et prénom. - * - * @param nom Le nom à rechercher. - * @param prenoms Le prénom à rechercher. - * @return La liste des utilisateurs correspondant au nom et prénom donnés. - */ - public List findByNomAndPrenoms(String nom, String prenoms) { - return find("nom = ?1 and prenoms = ?2", nom, prenoms).list(); - } - - /** - * Vérifie si un utilisateur avec un email donné existe. + * Vérifie si un utilisateur avec une adresse email spécifique existe. * * @param email L'email à vérifier. - * @return true si l'utilisateur existe, sinon false. + * @return true si un utilisateur avec cet email existe, sinon false. */ public boolean existsByEmail(String email) { - return count("email", email) > 0; + System.out.println("[LOG] Vérification de l'existence de l'utilisateur avec l'email : " + email); + long count = find("email", email).count(); + boolean exists = count > 0; + System.out.println("[LOG] Utilisateur existe : " + exists); + return exists; } /** - * Supprime un utilisateur par email. + * Supprime un utilisateur par son identifiant UUID. * - * @param email L'email de l'utilisateur à supprimer. - * @return Le nombre d'entrées supprimées (0 ou 1). + * @param id L'UUID de l'utilisateur à supprimer. + * @return true si l'utilisateur a été supprimé, sinon false. */ - @Transactional - public long deleteByEmail(String email) { - return delete("email", email); - } - - /** - * Recherche les utilisateurs par rôle. - * - * @param role Le rôle à rechercher. - * @return La liste des utilisateurs avec le rôle donné. - */ - public List findByRole(String role) { - return find("role", role).list(); - } - - /** - * Récupère une liste paginée d'utilisateurs. - * - * @param page Le numéro de la page (commençant à 0). - * @param size Le nombre d'éléments par page. - * @return Une liste paginée d'utilisateurs. - */ - public List findAllPaged(int page, int size) { - return findAll().page(page, size).list(); - } - - /** - * Compte le nombre total d'utilisateurs. - * - * @return Le nombre total d'utilisateurs. - */ - public long countAllUsers() { - return count(); - } - - /** - * Met à jour le mot de passe d'un utilisateur identifié par son email. - * - * @param email Le courriel de l'utilisateur. - * @param nouveauMotDePasse Le nouveau mot de passe. - * @return true si la mise à jour a réussi, sinon false. - */ - @Transactional - public boolean updatePasswordByEmail(String email, String nouveauMotDePasse) { - Users user = findByEmail(email); - if (user != null) { - user.setMotDePasse(hashPasswordSHA256(nouveauMotDePasse)); - return true; + public boolean deleteById(UUID id) { + System.out.println("[LOG] Suppression de l'utilisateur avec l'ID : " + id); + long deletedCount = delete("id", id); // Utiliser long pour récupérer le nombre d'enregistrements supprimés + boolean deleted = deletedCount > 0; // Convertir en boolean + if (deleted) { + System.out.println("[LOG] Utilisateur avec l'ID " + id + " supprimé avec succès."); + } else { + System.out.println("[LOG] Aucune suppression, utilisateur avec l'ID " + id + " introuvable."); } - return false; + return deleted; } - /** - * Recherche les utilisateurs qui ont créé un nombre spécifique d'événements. - * - * @param minEvents Le nombre minimum d'événements créés. - * @return La liste des utilisateurs ayant créé au moins le nombre d'événements spécifié. - */ - public List findByMinimumEventsCreated(int minEvents) { - return find("size(createdEvents) >= ?1", minEvents).list(); - } - - /** - * Recherche les utilisateurs participant à un événement spécifique. - * - * @param eventId L'ID de l'événement. - * @return La liste des utilisateurs participant à l'événement. - */ - public List findParticipantsByEventId(UUID eventId) { - return find("SELECT u FROM Users u JOIN u.participatedEvents e WHERE e.id = ?1", eventId).list(); - } - - /** - * Recherche les utilisateurs ayant aimé un événement spécifique. - * - * @param eventId L'ID de l'événement. - * @return La liste des utilisateurs ayant aimé l'événement. - */ - public List findUsersWhoLikedEvent(UUID eventId) { - // Remplacez par la logique de recherche appropriée en fonction du modèle de données "likes" - return find("SELECT u FROM Users u JOIN u.likedEvents e WHERE e.id = ?1", eventId).list(); - } - - /** - * Recherche les utilisateurs ayant créé un événement avec un titre spécifique. - * - * @param title Le titre de l'événement. - * @return La liste des utilisateurs ayant créé un événement avec le titre donné. - */ - public List findUsersByCreatedEventTitle(String title) { - return find("SELECT u FROM Users u JOIN u.createdEvents e WHERE e.title = ?1", title).list(); - } - - /** - * Met à jour le rôle d'un utilisateur par son ID. - * - * @param id L'ID de l'utilisateur. - * @param nouveauRole Le nouveau rôle. - * @return true si la mise à jour a réussi, sinon false. - */ - @Transactional - public boolean updateRoleById(UUID id, String nouveauRole) { - Users user = findById(id); - if (user != null) { - user.setRole(nouveauRole); - return true; - } - return false; - } - - /** - * Recherche les utilisateurs qui ne participent à aucun événement. - * - * @return La liste des utilisateurs ne participant à aucun événement. - */ - public List findUsersWithNoParticipation() { - return find("SELECT u FROM Users u WHERE size(u.participatedEvents) = 0").list(); - } - - /** - * Recherche les utilisateurs ayant un mot de passe spécifique (recherche de mot de passe). - * Note : Ceci est un cas d'usage rare et devrait être utilisé avec prudence. - * - * @param motDePasse Le mot de passe à rechercher. - * @return La liste des utilisateurs avec le mot de passe donné. - */ - public List findByMotDePasse(String motDePasse) { - return find("motDePasse", hashPasswordSHA256(motDePasse)).list(); - } - - /** - * Hachage du mot de passe avec SHA-256. - * - * @param motDePasse Le mot de passe à hacher. - * @return Le mot de passe haché en SHA-256. - */ - private String hashPasswordSHA256(String motDePasse) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] encodedhash = digest.digest(motDePasse.getBytes(StandardCharsets.UTF_8)); - return bytesToHex(encodedhash); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - /** - * Convertit un tableau de bytes en chaîne hexadécimale. - * - * @param hash Le tableau de bytes. - * @return La chaîne hexadécimale représentant le hash. - */ - private String bytesToHex(byte[] hash) { - StringBuilder hexString = new StringBuilder(2 * hash.length); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - return hexString.toString(); - } } diff --git a/src/main/java/com/lions/dev/resource/EventsResource.java b/src/main/java/com/lions/dev/resource/EventsResource.java index 424dc20..0890d05 100644 --- a/src/main/java/com/lions/dev/resource/EventsResource.java +++ b/src/main/java/com/lions/dev/resource/EventsResource.java @@ -1,384 +1,132 @@ package com.lions.dev.resource; -import com.lions.dev.entity.Events; -import com.lions.dev.entity.Users; +import com.lions.dev.entity.events.Events; import com.lions.dev.repository.EventsRepository; -import com.lions.dev.repository.UsersRepository; +import com.lions.dev.dto.request.events.EventRequestDTO; +import com.lions.dev.dto.response.events.EventResponseDTO; +import com.lions.dev.exception.EventNotFoundException; 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 java.time.LocalDateTime; import java.util.List; import java.util.UUID; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; +import org.jboss.logging.Logger; +/** + * Ressource REST pour la gestion des événements dans le système AfterWork. + * Cette classe expose des endpoints pour créer, récupérer, et supprimer des événements. + * + * Tous les logs nécessaires pour la traçabilité sont intégrés. + */ @Path("/events") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -@Tag(name = "Events", description = "Opérations liées à l'entité Events") +@Produces("application/json") +@Consumes("application/json") +@Tag(name = "Events", description = "Opérations liées à la gestion des événements") public class EventsResource { - @Inject - UsersRepository usersRepository; - @Inject EventsRepository eventsRepository; - /** - * Récupérer tous les événements. - * - * @return Liste de tous les événements. - */ - @GET - @Operation(summary = "Récupérer tous les événements", description = "Retourne une liste de tous les événements") - public List getAllEvents() { - // Log pour le début de la récupération des événements - System.out.println("Tentative de récupération de tous les événements."); - List events = eventsRepository.findAllEvents(); - // Log du nombre d'événements récupérés - System.out.println("Nombre d'événements récupérés: " + events.size()); - return events; - } + private static final Logger LOG = Logger.getLogger(EventsResource.class); /** - * Créer un nouvel événement. + * Endpoint pour créer un nouvel événement. * - * @param event L'événement à créer. - * @return Réponse HTTP indiquant le succès ou l'échec de la création. + * @param eventRequestDTO Le DTO contenant les informations de l'événement à créer. + * @return Une réponse HTTP contenant l'événement créé ou un message d'erreur. */ @POST @Transactional - @Operation(summary = "Créer un nouvel événement", description = "Crée un nouvel événement") - public Response createEvent(@Valid Events event) { - try { - // Validation de la date de l'événement - if (event.getEventDate() == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("La date de l'événement (eventDate) est requise.") - .build(); - } + @Operation(summary = "Créer un nouvel événement", description = "Crée un nouvel événement et retourne ses détails") + public Response createEvent(EventRequestDTO eventRequestDTO) { + LOG.info("Tentative de création d'un nouvel événement : " + eventRequestDTO.getTitle()); - // Validation de l'existence du créateur - if (event.getCreator() == null || event.getCreator().getId() == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("Les informations du créateur sont manquantes ou invalides.") - .build(); - } + Events event = new Events(); + event.setTitle(eventRequestDTO.getTitle()); + event.setStartDate(eventRequestDTO.getStartDate()); + event.setEndDate(eventRequestDTO.getEndDate()); + event.setCreator(eventRequestDTO.getCreator()); // Créateur de l'événement - UUID creatorId = event.getCreator().getId(); - Users creator = usersRepository.findById(creatorId); - if (creator == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("Créateur non trouvé.") - .build(); - } + eventsRepository.persist(event); + LOG.info("Événement créé avec succès : " + event.getTitle()); - // Associer le créateur et l'ajouter en tant que participant par défaut - event.setCreator(creator); - event.addParticipant(creator); - - // Log avant la persistance de l'événement - System.out.println("Tentative de persistance de l'événement: " + event.getTitle()); - eventsRepository.persist(event); - // Log après la persistance - System.out.println("Événement persisté avec succès: " + event.getId()); - - return Response.status(Response.Status.CREATED).entity(event).build(); - } catch (Exception e) { - e.printStackTrace(); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("Une erreur est survenue lors de la création de l'événement : " + e.getMessage()) - .build(); - } + EventResponseDTO responseDTO = new EventResponseDTO(event); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } /** - * Récupérer un événement par ID. + * Endpoint pour récupérer les détails d'un événement par ID. * * @param id L'ID de l'événement. - * @return L'événement correspondant à l'ID ou une réponse HTTP 404 si non trouvé. + * @return Une réponse HTTP contenant les informations de l'événement. */ @GET - @Path("{id}") - @Operation(summary = "Récupérer un événement par ID", description = "Retourne un événement par son ID") + @Path("/{id}") + @Operation(summary = "Récupérer un événement par ID", description = "Retourne les détails de l'événement demandé") public Response getEventById(@PathParam("id") UUID id) { - // Log pour la récupération par ID - System.out.println("Tentative de récupération de l'événement avec ID: " + id); + LOG.info("Récupération de l'événement avec l'ID : " + id); + Events event = eventsRepository.findById(id); if (event == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + id); - return Response.status(Response.Status.NOT_FOUND).build(); + LOG.warn("Événement non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND) + .entity("Événement non trouvé.").build(); } - // Log de la réussite de la récupération - System.out.println("Événement trouvé: " + event.getTitle()); - return Response.ok(event).build(); + + EventResponseDTO responseDTO = new EventResponseDTO(event); + LOG.info("Événement trouvé : " + event.getTitle()); + return Response.ok(responseDTO).build(); } /** - * Mettre à jour un événement existant. + * Endpoint pour récupérer une liste de tous les événements après une date donnée. * - * @param id L'ID de l'événement à mettre à jour. - * @param event Les nouvelles informations de l'événement. - * @return L'événement mis à jour ou une réponse HTTP 404 si non trouvé. + * @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. */ - @PUT - @Path("{id}") - @Transactional - @Operation(summary = "Mettre à jour un événement", description = "Met à jour un événement existant par ID") - public Response updateEvent(@PathParam("id") UUID id, @Valid Events event) { - // Log pour la tentative de mise à jour - System.out.println("Tentative de mise à jour de l'événement avec ID: " + id); - Events entity = eventsRepository.findById(id); - if (entity == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + id); - return Response.status(Response.Status.NOT_FOUND).build(); + @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("Récupération des événements après la date : " + startDate); + + List events = eventsRepository.findEventsAfterDate(startDate); + if (events.isEmpty()) { + LOG.warn("Aucun événement trouvé après la date : " + startDate); + return Response.status(Response.Status.NOT_FOUND) + .entity("Aucun événement trouvé après cette date.").build(); } - // Mise à jour des informations de l'événement - entity.setTitle(event.getTitle()); - entity.setDescription(event.getDescription()); - entity.setEventDate(event.getEventDate()); - entity.setLocation(event.getLocation()); - entity.setCategory(event.getCategory()); - entity.setLink(event.getLink()); - entity.setImageUrl(event.getImageUrl()); - - // Log après mise à jour - System.out.println("Événement mis à jour avec succès: " + entity.getId()); - return Response.ok(entity).build(); + List responseDTOs = events.stream().map(EventResponseDTO::new).toList(); + LOG.info("Nombre d'événements trouvés après la date : " + events.size()); + return Response.ok(responseDTOs).build(); } /** - * Supprimer un événement. + * Endpoint pour supprimer un événement par ID. * * @param id L'ID de l'événement à supprimer. - * @return Une réponse HTTP 204 (No Content) ou 404 si non trouvé. + * @return Une réponse HTTP indiquant le succès ou l'échec de la suppression. */ @DELETE - @Path("{id}") + @Path("/{id}") @Transactional - @Operation(summary = "Supprimer un événement", description = "Supprime un événement existant par ID") + @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 pour la tentative de suppression - System.out.println("Tentative de suppression de l'événement avec ID: " + id); - Events event = eventsRepository.findById(id); - if (event == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + id); - return Response.status(Response.Status.NOT_FOUND).build(); - } + LOG.info("Tentative de suppression de l'événement avec l'ID : " + id); - eventsRepository.delete(event); - // Log après suppression - System.out.println("Événement supprimé avec succès: " + id); - return Response.noContent().build(); - } - - /** - * Ajouter un participant à un événement. - * - * @param eventId L'ID de l'événement. - * @param userId L'ID de l'utilisateur à ajouter comme participant. - * @return L'événement mis à jour ou une réponse HTTP 404 si l'événement ou l'utilisateur est non trouvé. - */ - @POST - @Path("{eventId}/participants/{userId}") - @Transactional - @Operation(summary = "Ajouter un participant à un événement", description = "Ajoute un utilisateur en tant que participant à un événement") - public Response addParticipant(@PathParam("eventId") UUID eventId, @PathParam("userId") UUID userId) { - // Log pour l'ajout de participant - System.out.println("Tentative d'ajout du participant avec ID: " + userId + " à l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - Users user = usersRepository.findById(userId); - - if (event == null || user == null) { - // Log si l'événement ou l'utilisateur n'est pas trouvé - System.out.println("Événement ou utilisateur non trouvé. Event ID: " + eventId + ", User ID: " + userId); + boolean deleted = eventsRepository.deleteById(id); + if (deleted) { + LOG.info("Événement supprimé avec succès."); + return Response.noContent().build(); + } else { + LOG.warn("Échec de la suppression : événement introuvable avec l'ID : " + id); return Response.status(Response.Status.NOT_FOUND) - .entity("Événement ou utilisateur non trouvé.") - .build(); + .entity("Événement non trouvé.").build(); } - - event.addParticipant(user); - // Log après l'ajout de participant - System.out.println("Participant ajouté avec succès. Event ID: " + eventId + ", User ID: " + userId); - return Response.ok(event).build(); } - - /** - * Retirer un participant d'un événement. - * - * @param eventId L'ID de l'événement. - * @param userId L'ID de l'utilisateur à retirer comme participant. - * @return L'événement mis à jour ou une réponse HTTP 404 si l'événement ou l'utilisateur est non trouvé. - */ - @DELETE - @Path("{eventId}/participants/{userId}") - @Transactional - @Operation(summary = "Retirer un participant d'un événement", description = "Retire un utilisateur en tant que participant d'un événement") - public Response removeParticipant(@PathParam("eventId") UUID eventId, @PathParam("userId") UUID userId) { - // Log pour la tentative de retrait du participant - System.out.println("Tentative de retrait du participant avec ID: " + userId + " de l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - Users user = usersRepository.findById(userId); - - if (event == null || user == null) { - // Log si l'événement ou l'utilisateur n'est pas trouvé - System.out.println("Événement ou utilisateur non trouvé. Event ID: " + eventId + ", User ID: " + userId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement ou utilisateur non trouvé.") - .build(); - } - - event.removeParticipant(user); - // Log après le retrait du participant - System.out.println("Participant retiré avec succès. Event ID: " + eventId + ", User ID: " + userId); - return Response.ok(event).build(); - } - - /** - * Ajouter un "j'aime" à un événement. - * - * @param eventId L'ID de l'événement. - * @param userId L'ID de l'utilisateur qui aime l'événement. - * @return L'événement mis à jour ou une réponse HTTP 404 si l'événement ou l'utilisateur est non trouvé. - */ - @POST - @Path("{eventId}/like/{userId}") - @Transactional - @Operation(summary = "Ajouter un 'j'aime' à un événement", description = "Ajoute un utilisateur aux 'j'aime' d'un événement") - public Response likeEvent(@PathParam("eventId") UUID eventId, @PathParam("userId") UUID userId) { - // Log pour l'ajout d'un "j'aime" - System.out.println("Tentative d'ajout d'un 'j'aime' par l'utilisateur avec ID: " + userId + " pour l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - Users user = usersRepository.findById(userId); - - if (event == null || user == null) { - // Log si l'événement ou l'utilisateur n'est pas trouvé - System.out.println("Événement ou utilisateur non trouvé. Event ID: " + eventId + ", User ID: " + userId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement ou utilisateur non trouvé.") - .build(); - } - - event.addLike(user); - // Log après l'ajout du "j'aime" - System.out.println("'J'aime' ajouté avec succès. Event ID: " + eventId + ", User ID: " + userId); - return Response.ok(event).build(); - } - - /** - * Retirer un "j'aime" d'un événement. - * - * @param eventId L'ID de l'événement. - * @param userId L'ID de l'utilisateur qui retire son "j'aime". - * @return L'événement mis à jour ou une réponse HTTP 404 si l'événement ou l'utilisateur est non trouvé. - */ - @DELETE - @Path("{eventId}/like/{userId}") - @Transactional - @Operation(summary = "Retirer un 'j'aime' d'un événement", description = "Retire un utilisateur des 'j'aime' d'un événement") - public Response unlikeEvent(@PathParam("eventId") UUID eventId, @PathParam("userId") UUID userId) { - // Log pour la tentative de retrait d'un "j'aime" - System.out.println("Tentative de retrait d'un 'j'aime' par l'utilisateur avec ID: " + userId + " pour l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - Users user = usersRepository.findById(userId); - - if (event == null || user == null) { - // Log si l'événement ou l'utilisateur n'est pas trouvé - System.out.println("Événement ou utilisateur non trouvé. Event ID: " + eventId + ", User ID: " + userId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement ou utilisateur non trouvé.") - .build(); - } - - event.removeLike(user); - // Log après le retrait du "j'aime" - System.out.println("'J'aime' retiré avec succès. Event ID: " + eventId + ", User ID: " + userId); - return Response.ok(event).build(); - } - - /** - * Fermer un événement. - * - * @param eventId L'ID de l'événement à fermer. - * @return Une réponse HTTP indiquant le succès ou l'échec de la fermeture. - */ - @POST - @Path("{eventId}/close") - @Transactional - @Operation(summary = "Fermer un événement", description = "Ferme un événement existant") - public Response closeEvent(@PathParam("eventId") UUID eventId) { - // Log pour la tentative de fermeture de l'événement - System.out.println("Tentative de fermeture de l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - - if (event == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + eventId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement non trouvé.") - .build(); - } - - if ("CLOSED".equals(event.getStatus())) { - // Log si l'événement est déjà fermé - System.out.println("L'événement est déjà fermé: " + eventId); - return Response.status(Response.Status.BAD_REQUEST) - .entity("L'événement est déjà fermé.") - .build(); - } - - event.setStatus("CLOSED"); - eventsRepository.persist(event); - // Log après la fermeture de l'événement - System.out.println("Événement fermé avec succès: " + eventId); - return Response.ok("Événement fermé avec succès.").build(); - } - - /** - * Rouvrir un événement. - * - * @param eventId L'ID de l'événement à rouvrir. - * @return Une réponse HTTP indiquant le succès ou l'échec de la réouverture. - */ - @POST - @Path("{eventId}/reopen") - @Transactional - @Operation(summary = "Rouvrir un événement", description = "Rouvre un événement existant qui est actuellement fermé") - public Response reopenEvent(@PathParam("eventId") UUID eventId) { - // Log pour la tentative de réouverture de l'événement - System.out.println("Tentative de réouverture de l'événement avec ID: " + eventId); - Events event = eventsRepository.findById(eventId); - - if (event == null) { - // Log si l'événement n'est pas trouvé - System.out.println("Événement non trouvé: " + eventId); - return Response.status(Response.Status.NOT_FOUND) - .entity("Événement non trouvé.") - .build(); - } - - if (!"CLOSED".equals(event.getStatus())) { - // Log si l'événement n'est pas fermé - System.out.println("L'événement n'est pas fermé, donc il ne peut pas être rouvert: " + eventId); - return Response.status(Response.Status.BAD_REQUEST) - .entity("L'événement n'est pas fermé et ne peut pas être rouvert.") - .build(); - } - - // Rouvrir l'événement - event.setStatus("OPEN"); - eventsRepository.persist(event); - // Log après la réouverture de l'événement - System.out.println("Événement rouvert avec succès: " + eventId); - return Response.ok("Événement rouvert avec succès.").build(); - } - } diff --git a/src/main/java/com/lions/dev/resource/UsersResource.java b/src/main/java/com/lions/dev/resource/UsersResource.java index 35bc0e4..bb180b1 100644 --- a/src/main/java/com/lions/dev/resource/UsersResource.java +++ b/src/main/java/com/lions/dev/resource/UsersResource.java @@ -1,143 +1,142 @@ package com.lions.dev.resource; -import com.lions.dev.entity.Users; +import com.lions.dev.entity.users.Users; import com.lions.dev.repository.UsersRepository; +import com.lions.dev.dto.request.users.UserRequestDTO; +import com.lions.dev.dto.response.users.UserResponseDTO; +import com.lions.dev.exception.UserNotFoundException; import jakarta.inject.Inject; import jakarta.transaction.Transactional; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import lombok.Getter; -import lombok.Setter; +import java.time.LocalDateTime; +import java.util.UUID; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; -import java.util.List; -import java.util.UUID; +import org.jboss.logging.Logger; /** - * Ressource REST pour gérer les entités Users. + * Ressource REST pour la gestion des utilisateurs dans le système AfterWork. + * Cette classe expose des endpoints pour créer, authentifier, récupérer et supprimer des utilisateurs. + * + * Tous les logs nécessaires pour la traçabilité sont intégrés. */ @Path("/users") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) -@Tag(name = "Users", description = "Opérations liées à l'entité Users") +@Produces("application/json") +@Consumes("application/json") +@Tag(name = "Users", description = "Opérations liées à la gestion des utilisateurs") public class UsersResource { @Inject UsersRepository usersRepository; - /** - * Récupère tous les utilisateurs. - * - * @return Liste des utilisateurs. - */ - @GET - @Operation(summary = "Récupérer tous les utilisateurs", description = "Retourne une liste de tous les utilisateurs") - public List getAllUsers() { - return usersRepository.listAll(); - } + private static final Logger LOG = Logger.getLogger(UsersResource.class); /** - * Crée un nouvel utilisateur. + * Endpoint pour créer un nouvel utilisateur. * - * @param user L'utilisateur à créer. - * @return L'utilisateur créé. + * @param userRequestDTO Le DTO contenant les informations de l'utilisateur à créer. + * @return Une réponse HTTP contenant l'utilisateur créé ou un message d'erreur. */ @POST @Transactional - @Operation(summary = "Créer un nouvel utilisateur", description = "Crée un nouvel utilisateur") - public Response createUser(@Valid Users user) { - if (user.getId() != null && usersRepository.findById(user.getId()) != null) { + @Operation(summary = "Créer un nouvel utilisateur", description = "Crée un nouvel utilisateur et retourne les détails") + public Response createUser(UserRequestDTO userRequestDTO) { + LOG.info("Tentative de création d'un nouvel utilisateur avec l'email : " + userRequestDTO.getEmail()); + + if (usersRepository.existsByEmail(userRequestDTO.getEmail())) { + LOG.warn("Un utilisateur avec cet email existe déjà : " + userRequestDTO.getEmail()); return Response.status(Response.Status.CONFLICT) - .entity("L'utilisateur avec l'ID " + user.getId() + " existe déjà.") - .build(); + .entity("Un utilisateur avec cet email existe déjà.").build(); } - if (user.getMotDePasse() == null || user.getMotDePasse().isEmpty()) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("Le mot de passe est obligatoire.") - .build(); + Users user = new Users(); + user.setNom(userRequestDTO.getNom()); + user.setPrenoms(userRequestDTO.getPrenoms()); + user.setEmail(userRequestDTO.getEmail()); + user.setMotDePasse(userRequestDTO.getMotDePasse()); // Hachage automatique dans l'entité + // Assigner un rôle par défaut si non fourni (par exemple : USER) + if (user.getRole() == null) { + user.setRole("USER"); // Définir le rôle par défaut } usersRepository.persist(user); - return Response.status(Response.Status.CREATED).entity(user).build(); + LOG.info("Utilisateur créé avec succès : " + user.getEmail() + " à " + LocalDateTime.now()); + + UserResponseDTO responseDTO = new UserResponseDTO(user); + return Response.status(Response.Status.CREATED).entity(responseDTO).build(); } /** - * Authentifie un utilisateur avec son email et mot de passe. + * Endpoint pour authentifier un utilisateur. * - * @param credentials Les identifiants de l'utilisateur. - * @return L'utilisateur authentifié. + * @param userRequestDTO Le DTO contenant les informations d'authentification. + * @return Une réponse HTTP indiquant si l'authentification a réussi ou échoué. */ @POST @Path("/authenticate") - @Transactional - @Operation(summary = "Authentifier un utilisateur", description = "Authentifie un utilisateur avec email et mot de passe") - public Response authenticateUser(@Valid UserCredentials credentials) { - Users user = usersRepository.find("email", credentials.getEmail()).firstResult(); - if (user == null || !user.getMotDePasse().equals(credentials.getMotDePasse())) { - return Response.status(Response.Status.UNAUTHORIZED) - .entity("Email ou mot de passe incorrect") - .build(); + @Operation(summary = "Authentifier un utilisateur", description = "Vérifie les informations de connexion de l'utilisateur") + public Response authenticateUser(UserRequestDTO userRequestDTO) { + LOG.info("Tentative d'authentification pour l'utilisateur avec l'email : " + userRequestDTO.getEmail()); + + Users user = usersRepository.findByEmail(userRequestDTO.getEmail()) + .orElseThrow(() -> new UserNotFoundException("Utilisateur non trouvé avec l'email : " + userRequestDTO.getEmail())); + + if (!user.verifierMotDePasse(userRequestDTO.getMotDePasse())) { + LOG.warn("Échec de l'authentification : mot de passe incorrect pour l'email : " + userRequestDTO.getEmail()); + return Response.status(Response.Status.UNAUTHORIZED).entity("Mot de passe incorrect.").build(); } - return Response.ok(user).build(); + + LOG.info("Authentification réussie pour l'utilisateur : " + user.getEmail()); + UserResponseDTO responseDTO = new UserResponseDTO(user); + return Response.ok(responseDTO).build(); } /** - * Met à jour un utilisateur existant. + * Endpoint pour récupérer les détails d'un utilisateur par ID. * - * @param id L'ID de l'utilisateur à mettre à jour. - * @param user Les nouvelles informations de l'utilisateur. - * @return L'utilisateur mis à jour. + * @param id L'ID de l'utilisateur. + * @return Une réponse HTTP contenant les informations de l'utilisateur. */ - @PUT - @Path("{id}") - @Transactional - @Operation(summary = "Mettre à jour un utilisateur", description = "Met à jour un utilisateur existant par ID") - public Response updateUser(@PathParam("id") UUID id, @Valid Users user) { - Users entity = usersRepository.findById(id); - if (entity == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + @GET + @Path("/{id}") + @Operation(summary = "Récupérer un utilisateur par ID", description = "Retourne les détails de l'utilisateur demandé") + public Response getUserById(@PathParam("id") UUID id) { + LOG.info("Récupération de l'utilisateur avec l'ID : " + id); + + Users user = usersRepository.findById(id); + if (user == null) { + LOG.warn("Utilisateur non trouvé avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND) + .entity("Utilisateur non trouvé.").build(); } - entity.setNom(user.getNom()); - entity.setPrenoms(user.getPrenoms()); - entity.setEmail(user.getEmail()); - entity.setMotDePasse(user.getMotDePasse()); - return Response.ok(entity).build(); + + UserResponseDTO responseDTO = new UserResponseDTO(user); + LOG.info("Utilisateur trouvé : " + user.getEmail()); + return Response.ok(responseDTO).build(); } /** - * Supprime un utilisateur existant. + * Endpoint pour supprimer un utilisateur par ID. * * @param id L'ID de l'utilisateur à supprimer. - * @return Une réponse vide avec le statut HTTP approprié. + * @return Une réponse HTTP indiquant le succès ou l'échec de la suppression. */ @DELETE - @Path("{id}") + @Path("/{id}") @Transactional - @Operation(summary = "Supprimer un utilisateur", description = "Supprime un utilisateur existant par ID") + @Operation(summary = "Supprimer un utilisateur", description = "Supprime un utilisateur de la base de données") public Response deleteUser(@PathParam("id") UUID id) { + LOG.info("Tentative de suppression de l'utilisateur avec l'ID : " + id); + boolean deleted = usersRepository.deleteById(id); - if (!deleted) { - return Response.status(Response.Status.NOT_FOUND).build(); + if (deleted) { + LOG.info("Utilisateur supprimé avec succès."); + return Response.noContent().build(); + } else { + LOG.warn("Échec de la suppression : utilisateur introuvable avec l'ID : " + id); + return Response.status(Response.Status.NOT_FOUND) + .entity("Utilisateur non trouvé.").build(); } - return Response.noContent().build(); - } - - /** - * Classe pour les identifiants de l'utilisateur lors de l'authentification. - */ - @Setter - @Getter - public static class UserCredentials { - @NotNull - @Email - private String email; - - @NotNull - private String motDePasse; } } diff --git a/src/main/java/com/lions/dev/service/EventService.java b/src/main/java/com/lions/dev/service/EventService.java new file mode 100644 index 0000000..4b0d18b --- /dev/null +++ b/src/main/java/com/lions/dev/service/EventService.java @@ -0,0 +1,86 @@ +package com.lions.dev.service; + +import com.lions.dev.entity.events.Events; +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.EventsRepository; +import com.lions.dev.dto.request.events.EventRequestDTO; +import com.lions.dev.exception.EventNotFoundException; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import java.time.LocalDateTime; +import java.util.List; +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. + */ +@ApplicationScoped +public class EventService { + + @Inject + EventsRepository eventsRepository; + + /** + * Crée un nouvel événement dans le système. + * + * @param eventRequestDTO Le DTO contenant les informations de l'événement à créer. + * @param creator L'utilisateur créateur de l'événement. + * @return L'événement créé. + */ + public Events createEvent(EventRequestDTO eventRequestDTO, Users creator) { + Events event = new Events(); + event.setTitle(eventRequestDTO.getTitle()); + event.setStartDate(eventRequestDTO.getStartDate()); + event.setEndDate(eventRequestDTO.getEndDate()); + event.setCreator(creator); + eventsRepository.persist(event); + System.out.println("[LOG] Événement créé : " + event.getTitle()); + return event; + } + + /** + * Récupère un événement par son ID. + * + * @param id L'ID de l'événement. + * @return L'événement trouvé. + * @throws EventNotFoundException Si l'événement n'est pas trouvé. + */ + public Events getEventById(UUID id) { + Events event = eventsRepository.findById(id); + if (event == null) { + System.out.println("[ERROR] Événement non trouvé avec l'ID : " + id); + throw new EventNotFoundException("Événement non trouvé avec l'ID : " + id); + } + System.out.println("[LOG] É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. + */ + public List getEventsAfterDate(LocalDateTime startDate) { + List events = eventsRepository.findEventsAfterDate(startDate); + System.out.println("[LOG] Nombre d'événements trouvés après la date " + startDate + " : " + events.size()); + return events; + } + + /** + * Supprime un événement par son ID. + * + * @param id L'ID de l'événement à supprimer. + * @return true si l'événement a été supprimé, false sinon. + */ + public boolean deleteEvent(UUID id) { + boolean deleted = eventsRepository.deleteById(id); + if (deleted) { + System.out.println("[LOG] Événement supprimé avec succès : " + id); + } else { + System.out.println("[ERROR] Échec de la suppression de l'événement avec l'ID : " + id); + } + return deleted; + } +} diff --git a/src/main/java/com/lions/dev/service/UserService.java b/src/main/java/com/lions/dev/service/UserService.java new file mode 100644 index 0000000..f7ad42c --- /dev/null +++ b/src/main/java/com/lions/dev/service/UserService.java @@ -0,0 +1,89 @@ +package com.lions.dev.service; + +import com.lions.dev.entity.users.Users; +import com.lions.dev.repository.UsersRepository; +import com.lions.dev.dto.request.users.UserRequestDTO; +import com.lions.dev.exception.UserNotFoundException; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import java.util.Optional; +import java.util.UUID; + +/** + * Service de gestion des utilisateurs. + * Ce service contient la logique métier pour la création, récupération et suppression des utilisateurs. + */ +@ApplicationScoped +public class UserService { + + @Inject + UsersRepository usersRepository; + + /** + * Crée un nouvel utilisateur dans le système. + * + * @param userRequestDTO Le DTO contenant les informations de l'utilisateur à créer. + * @return L'utilisateur créé. + */ + public Users createUser(UserRequestDTO userRequestDTO) { + Users user = new Users(); + user.setNom(userRequestDTO.getNom()); + user.setPrenoms(userRequestDTO.getPrenoms()); + user.setEmail(userRequestDTO.getEmail()); + user.setMotDePasse(userRequestDTO.getMotDePasse()); // Hachage automatique + usersRepository.persist(user); + System.out.println("[LOG] Utilisateur créé : " + user.getEmail()); + return user; + } + + /** + * Authentifie un utilisateur avec son email et son mot de passe. + * + * @param email L'email de l'utilisateur. + * @param motDePasse Le mot de passe de l'utilisateur. + * @return L'utilisateur authentifié. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé ou si le mot de passe est incorrect. + */ + public Users authenticateUser(String email, String motDePasse) { + Optional userOptional = usersRepository.findByEmail(email); + if (userOptional.isEmpty() || !userOptional.get().verifierMotDePasse(motDePasse)) { + System.out.println("[ERROR] Échec de l'authentification pour l'email : " + email); + throw new UserNotFoundException("Utilisateur ou mot de passe incorrect."); + } + System.out.println("[LOG] Utilisateur authentifié : " + email); + return userOptional.get(); + } + + /** + * Récupère un utilisateur par son ID. + * + * @param id L'ID de l'utilisateur. + * @return L'utilisateur trouvé. + * @throws UserNotFoundException Si l'utilisateur n'est pas trouvé. + */ + public Users getUserById(UUID id) { + Users user = usersRepository.findById(id); + if (user == null) { + System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + id); + throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + id); + } + System.out.println("[LOG] Utilisateur trouvé avec l'ID : " + id); + return user; + } + + /** + * Supprime un utilisateur par son ID. + * + * @param id L'ID de l'utilisateur à supprimer. + * @return true si l'utilisateur a été supprimé, false sinon. + */ + public boolean deleteUser(UUID id) { + boolean deleted = usersRepository.deleteById(id); + if (deleted) { + System.out.println("[LOG] Utilisateur supprimé avec succès : " + id); + } else { + System.out.println("[ERROR] Échec de la suppression de l'utilisateur avec l'ID : " + id); + } + return deleted; + } +} diff --git a/src/main/java/com/lions/dev/util/DateFormatter.java b/src/main/java/com/lions/dev/util/DateFormatter.java new file mode 100644 index 0000000..03b3e11 --- /dev/null +++ b/src/main/java/com/lions/dev/util/DateFormatter.java @@ -0,0 +1,35 @@ +package com.lions.dev.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Utilitaire pour la gestion et le formatage des dates dans l'application AfterWork. + */ +public class DateFormatter { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm"); + + /** + * Formate une date LocalDateTime dans un format lisible. + * + * @param date La date à formater. + * @return Une chaîne de caractères représentant la date formatée. + */ + public static String formatDate(LocalDateTime date) { + if (date == null) { + return ""; + } + return date.format(formatter); + } + + /** + * Convertit une chaîne de caractères en LocalDateTime selon le format défini. + * + * @param dateString La chaîne de caractères représentant la date. + * @return La date convertie en LocalDateTime. + */ + public static LocalDateTime parseDate(String dateString) { + return LocalDateTime.parse(dateString, formatter); + } +} diff --git a/src/main/java/com/lions/dev/util/InputConverter.java b/src/main/java/com/lions/dev/util/InputConverter.java new file mode 100644 index 0000000..89cb2a8 --- /dev/null +++ b/src/main/java/com/lions/dev/util/InputConverter.java @@ -0,0 +1,39 @@ +package com.lions.dev.util; + +/** + * Utilitaire pour la conversion des entrées dans le système AfterWork. + * Ce fichier peut être étendu pour inclure d'autres méthodes de conversion. + */ +public class InputConverter { + + /** + * Convertit une chaîne de caractères en entier. + * + * @param value La chaîne de caractères à convertir. + * @return Un entier ou null si la chaîne ne peut pas être convertie. + */ + public static Integer stringToInteger(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + System.out.println("[ERROR] Impossible de convertir la valeur en entier : " + value); + return null; + } + } + + /** + * Convertit une chaîne de caractères en booléen. + * + * @param value La chaîne de caractères à convertir. + * @return Un booléen ou false si la chaîne ne correspond pas à une valeur booléenne valide. + */ + public static boolean stringToBoolean(String value) { + if ("true".equalsIgnoreCase(value)) { + return true; + } else if ("false".equalsIgnoreCase(value)) { + return false; + } + System.out.println("[ERROR] Valeur non valide pour un booléen : " + value); + return false; + } +} diff --git a/src/main/java/com/lions/dev/util/SecureStorage.java b/src/main/java/com/lions/dev/util/SecureStorage.java new file mode 100644 index 0000000..ca718ff --- /dev/null +++ b/src/main/java/com/lions/dev/util/SecureStorage.java @@ -0,0 +1,49 @@ +package com.lions.dev.util; + +import jakarta.enterprise.context.ApplicationScoped; +import java.util.Base64; + +/** + * Classe utilitaire pour le stockage sécurisé de données sensibles. + * Elle peut être utilisée pour stocker et récupérer des informations sensibles telles que des jetons d'accès. + */ +@ApplicationScoped +public class SecureStorage { + + /** + * Encode des données sensibles en base64 pour les stocker de manière sécurisée. + * + * @param data Les données à encoder. + * @return Les données encodées en base64. + */ + public String encodeData(String data) { + if (data == null || data.isEmpty()) { + return ""; + } + return Base64.getEncoder().encodeToString(data.getBytes()); + } + + /** + * Décode des données encodées en base64 pour les utiliser. + * + * @param encodedData Les données encodées en base64. + * @return Les données décodées en texte clair. + */ + public String decodeData(String encodedData) { + if (encodedData == null || encodedData.isEmpty()) { + return ""; + } + return new String(Base64.getDecoder().decode(encodedData)); + } + + /** + * Supprime les données sensibles de manière sécurisée. + * + * @param data Les données à effacer. + */ + public void clearData(String data) { + System.out.println("[LOG] Les données ont été effacées de manière sécurisée."); + // En Java, il n'y a pas de suppression directe des données en mémoire. On peut ici + // gérer la suppression logique ou l'effacement de données dans un fichier sécurisé. + } +} diff --git a/src/main/java/com/lions/dev/util/Validators.java b/src/main/java/com/lions/dev/util/Validators.java new file mode 100644 index 0000000..2b18cec --- /dev/null +++ b/src/main/java/com/lions/dev/util/Validators.java @@ -0,0 +1,52 @@ +package com.lions.dev.util; + +import java.util.regex.Pattern; + +/** + * Classe utilitaire pour valider les données d'entrée dans l'application AfterWork. + * Elle contient des méthodes pour valider des emails, des numéros de téléphone, etc. + */ +public class Validators { + + private static final Pattern EMAIL_PATTERN = + Pattern.compile("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$"); + + private static final Pattern PHONE_PATTERN = + Pattern.compile("^\\+?[0-9]{7,15}$"); + + /** + * Valide si une chaîne de caractères est un email valide. + * + * @param email L'email à valider. + * @return true si l'email est valide, false sinon. + */ + public static boolean isValidEmail(String email) { + if (email == null || email.isEmpty()) { + return false; + } + return EMAIL_PATTERN.matcher(email).matches(); + } + + /** + * Valide si une chaîne de caractères est un numéro de téléphone valide. + * + * @param phoneNumber Le numéro de téléphone à valider. + * @return true si le numéro de téléphone est valide, false sinon. + */ + public static boolean isValidPhoneNumber(String phoneNumber) { + if (phoneNumber == null || phoneNumber.isEmpty()) { + return false; + } + return PHONE_PATTERN.matcher(phoneNumber).matches(); + } + + /** + * Valide si un mot de passe respecte les règles de sécurité (taille minimale). + * + * @param password Le mot de passe à valider. + * @return true si le mot de passe est sécurisé, false sinon. + */ + public static boolean isValidPassword(String password) { + return password != null && password.length() >= 6; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cc53cf7..880540b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,20 @@ +# Configuration Quarkus quarkus.http.port=8085 +# Configuration Swagger UI quarkus.swagger-ui.always-include=true quarkus.swagger-ui.path=/q/swagger-ui -]quarkus.smallrye-openapi.path=/openapi +quarkus.smallrye-openapi.path=/openapi +# Configuration de la base de données quarkus.datasource.db-kind=oracle -quarkus.datasource.jdbc.url=jdbc:oracle:thin:@localhost:1521:ORCLCDB +quarkus.datasource.jdbc.url=jdbc:oracle:thin:@localhost:1522:ORCLCDB quarkus.datasource.username=C##AFTERWORK quarkus.datasource.password=afterwork -quarkus.hibernate-orm.database.generation=drop-and-create quarkus.datasource.jdbc.driver=oracle.jdbc.OracleDriver +quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.log.sql=true -quarkus.datasource.devservices.enabled=false \ No newline at end of file +quarkus.datasource.devservices.enabled=false + +# Niveau de logging +quarkus.log.level=INFO diff --git a/src/test/java/com/lions/dev/GreetingResourceIT.java b/src/test/java/com/lions/dev/GreetingResourceIT.java deleted file mode 100644 index a3a8a36..0000000 --- a/src/test/java/com/lions/dev/GreetingResourceIT.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.lions.dev; - -import io.quarkus.test.junit.QuarkusIntegrationTest; - -@QuarkusIntegrationTest -class GreetingResourceIT extends GreetingResourceTest { - // Execute the same tests but in packaged mode. -} diff --git a/src/test/java/com/lions/dev/GreetingResourceTest.java b/src/test/java/com/lions/dev/GreetingResourceTest.java deleted file mode 100644 index 985a451..0000000 --- a/src/test/java/com/lions/dev/GreetingResourceTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.lions.dev; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -@QuarkusTest -class GreetingResourceTest { - @Test - void testHelloEndpoint() { - given() - .when().get("/hello") - .then() - .statusCode(200) - .body(is("Hello RESTEasy")); - } - -} \ No newline at end of file