Task 1.2 - Entités JPA fondamentales

- Création de BaseEntity avec audit trail et soft delete
- Création de l'entité User avec Quarkus Security JPA
- Création de l'entité Client avec informations d'entreprise
- Création de l'entité Coach avec informations professionnelles
- Relations JPA one-to-one entre User-Client et User-Coach
- Migrations Flyway V1, V2, V3 pour les tables
- Données de test dans import.sql
- Compilation réussie du module d'implémentation
This commit is contained in:
dahoud
2025-10-06 20:11:18 +00:00
parent e4d125e14c
commit 9d8ce834e8
10 changed files with 2127 additions and 429 deletions

View File

@@ -0,0 +1,432 @@
package com.gbcm.server.impl.entity;
import com.gbcm.server.api.enums.UserRole;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.List;
/**
* Entité représentant un utilisateur de la plateforme GBCM.
* Utilisée pour l'authentification et l'autorisation avec Quarkus Security.
*
* @author GBCM Development Team
* @version 1.0
* @since 1.0
*/
@Entity
@Table(name = "users", indexes = {
@Index(name = "idx_users_email", columnList = "email", unique = true),
@Index(name = "idx_users_role", columnList = "role"),
@Index(name = "idx_users_active", columnList = "active"),
@Index(name = "idx_users_deleted", columnList = "deleted")
})
@UserDefinition
@NamedQueries({
@NamedQuery(name = "User.findByEmail",
query = "SELECT u FROM User u WHERE u.email = :email AND u.deleted = false"),
@NamedQuery(name = "User.findActiveUsers",
query = "SELECT u FROM User u WHERE u.active = true AND u.deleted = false"),
@NamedQuery(name = "User.findByRole",
query = "SELECT u FROM User u WHERE u.role = :role AND u.deleted = false"),
@NamedQuery(name = "User.searchByNameOrEmail",
query = "SELECT u FROM User u WHERE (LOWER(u.firstName) LIKE LOWER(:search) OR LOWER(u.lastName) LIKE LOWER(:search) OR LOWER(u.email) LIKE LOWER(:search)) AND u.deleted = false")
})
public class User extends BaseEntity {
/**
* Identifiant unique de l'utilisateur.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* Prénom de l'utilisateur.
*/
@Column(name = "first_name", nullable = false, length = 50)
@NotBlank(message = "Le prénom est obligatoire")
@Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères")
private String firstName;
/**
* Nom de famille de l'utilisateur.
*/
@Column(name = "last_name", nullable = false, length = 50)
@NotBlank(message = "Le nom est obligatoire")
@Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
private String lastName;
/**
* Adresse email unique de l'utilisateur.
* Utilisée comme nom d'utilisateur pour l'authentification.
*/
@Column(name = "email", nullable = false, unique = true, length = 255)
@NotBlank(message = "L'email est obligatoire")
@Email(message = "Format d'email invalide")
@Size(max = 255, message = "L'email ne peut pas dépasser 255 caractères")
@Username
private String email;
/**
* Mot de passe haché de l'utilisateur.
* Utilisé pour l'authentification avec Quarkus Security.
*/
@Column(name = "password_hash", nullable = false, length = 255)
@NotBlank(message = "Le mot de passe est obligatoire")
@Size(max = 255, message = "Le hash du mot de passe ne peut pas dépasser 255 caractères")
@Password
private String passwordHash;
/**
* Numéro de téléphone de l'utilisateur.
*/
@Column(name = "phone", length = 20)
@Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères")
private String phone;
/**
* Rôle de l'utilisateur dans le système.
* Détermine les permissions et l'accès aux fonctionnalités.
*/
@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false, length = 20)
@NotNull(message = "Le rôle est obligatoire")
@Roles
private UserRole role;
/**
* Statut d'activation du compte utilisateur.
* true = compte actif, false = compte désactivé.
*/
@Column(name = "active", nullable = false)
private boolean active = true;
/**
* Date de dernière connexion de l'utilisateur.
*/
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
/**
* Adresse IP de la dernière connexion.
*/
@Column(name = "last_login_ip", length = 45)
@Size(max = 45, message = "L'adresse IP ne peut pas dépasser 45 caractères")
private String lastLoginIp;
/**
* Nombre de tentatives de connexion échouées consécutives.
*/
@Column(name = "failed_login_attempts", nullable = false)
private int failedLoginAttempts = 0;
/**
* Date de verrouillage du compte (après trop de tentatives échouées).
*/
@Column(name = "locked_until")
private LocalDateTime lockedUntil;
/**
* Token de réinitialisation de mot de passe.
*/
@Column(name = "password_reset_token", length = 255)
@Size(max = 255, message = "Le token de réinitialisation ne peut pas dépasser 255 caractères")
private String passwordResetToken;
/**
* Date d'expiration du token de réinitialisation.
*/
@Column(name = "password_reset_expires_at")
private LocalDateTime passwordResetExpiresAt;
/**
* Constructeur par défaut.
*/
public User() {
super();
}
/**
* Constructeur avec les champs obligatoires.
*
* @param firstName le prénom
* @param lastName le nom de famille
* @param email l'adresse email
* @param passwordHash le mot de passe haché
* @param role le rôle de l'utilisateur
*/
public User(String firstName, String lastName, String email, String passwordHash, UserRole role) {
this();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.passwordHash = passwordHash;
this.role = role;
}
/**
* Retourne le nom complet de l'utilisateur.
*
* @return le nom complet (prénom + nom)
*/
public String getFullName() {
return firstName + " " + lastName;
}
/**
* Vérifie si le compte est verrouillé.
*
* @return true si le compte est verrouillé, false sinon
*/
public boolean isLocked() {
return lockedUntil != null && LocalDateTime.now().isBefore(lockedUntil);
}
/**
* Verrouille le compte pour une durée spécifiée.
*
* @param lockDurationMinutes durée de verrouillage en minutes
*/
public void lockAccount(int lockDurationMinutes) {
this.lockedUntil = LocalDateTime.now().plusMinutes(lockDurationMinutes);
}
/**
* Déverrouille le compte et remet à zéro les tentatives échouées.
*/
public void unlockAccount() {
this.lockedUntil = null;
this.failedLoginAttempts = 0;
}
/**
* Incrémente le nombre de tentatives de connexion échouées.
*/
public void incrementFailedLoginAttempts() {
this.failedLoginAttempts++;
}
/**
* Remet à zéro les tentatives de connexion échouées.
*/
public void resetFailedLoginAttempts() {
this.failedLoginAttempts = 0;
}
/**
* Met à jour les informations de dernière connexion.
*
* @param ipAddress l'adresse IP de connexion
*/
public void updateLastLogin(String ipAddress) {
this.lastLoginAt = LocalDateTime.now();
this.lastLoginIp = ipAddress;
resetFailedLoginAttempts();
}
/**
* Génère un token de réinitialisation de mot de passe.
*
* @param token le token généré
* @param expirationHours durée de validité en heures
*/
public void setPasswordResetToken(String token, int expirationHours) {
this.passwordResetToken = token;
this.passwordResetExpiresAt = LocalDateTime.now().plusHours(expirationHours);
}
/**
* Efface le token de réinitialisation de mot de passe.
*/
public void clearPasswordResetToken() {
this.passwordResetToken = null;
this.passwordResetExpiresAt = null;
}
/**
* Vérifie si le token de réinitialisation est valide.
*
* @param token le token à vérifier
* @return true si le token est valide, false sinon
*/
public boolean isPasswordResetTokenValid(String token) {
return passwordResetToken != null &&
passwordResetToken.equals(token) &&
passwordResetExpiresAt != null &&
LocalDateTime.now().isBefore(passwordResetExpiresAt);
}
/**
* Méthode de recherche par email.
*
* @param email l'adresse email à rechercher
* @return l'utilisateur trouvé ou null
*/
public static User findByEmail(String email) {
return find("#User.findByEmail", email).firstResult();
}
/**
* Méthode de recherche des utilisateurs actifs.
*
* @return la liste des utilisateurs actifs
*/
public static List<User> findActiveUsers() {
return find("#User.findActiveUsers").list();
}
/**
* Méthode de recherche par rôle.
*
* @param role le rôle à rechercher
* @return la liste des utilisateurs avec ce rôle
*/
public static List<User> findByRole(UserRole role) {
return find("#User.findByRole", role).list();
}
/**
* Méthode de recherche par nom ou email.
*
* @param search le terme de recherche
* @return la liste des utilisateurs correspondants
*/
public static List<User> searchByNameOrEmail(String search) {
String searchPattern = "%" + search + "%";
return find("#User.searchByNameOrEmail", searchPattern).list();
}
// Getters et Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPasswordHash() {
return passwordHash;
}
public void setPasswordHash(String passwordHash) {
this.passwordHash = passwordHash;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public UserRole getRole() {
return role;
}
public void setRole(UserRole role) {
this.role = role;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public LocalDateTime getLastLoginAt() {
return lastLoginAt;
}
public void setLastLoginAt(LocalDateTime lastLoginAt) {
this.lastLoginAt = lastLoginAt;
}
public String getLastLoginIp() {
return lastLoginIp;
}
public void setLastLoginIp(String lastLoginIp) {
this.lastLoginIp = lastLoginIp;
}
public int getFailedLoginAttempts() {
return failedLoginAttempts;
}
public void setFailedLoginAttempts(int failedLoginAttempts) {
this.failedLoginAttempts = failedLoginAttempts;
}
public LocalDateTime getLockedUntil() {
return lockedUntil;
}
public void setLockedUntil(LocalDateTime lockedUntil) {
this.lockedUntil = lockedUntil;
}
public String getPasswordResetToken() {
return passwordResetToken;
}
public LocalDateTime getPasswordResetExpiresAt() {
return passwordResetExpiresAt;
}
public void setPasswordResetExpiresAt(LocalDateTime passwordResetExpiresAt) {
this.passwordResetExpiresAt = passwordResetExpiresAt;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", role=" + role +
", active=" + active +
", lastLoginAt=" + lastLoginAt +
", failedLoginAttempts=" + failedLoginAttempts +
", locked=" + isLocked() +
'}';
}
}