Files
gbcm-server-impl-quarkus/src/main/java/com/gbcm/server/impl/resource/ClientResource.java
dahoud 7c59d903bc PHASE 2 - Développement complet des fonctionnalités Client et Coach
 NOUVELLES FONCTIONNALITÉS MAJEURES AJOUTÉES :

🔧 SERVICES ET INTERFACES :
- ClientService interface avec toutes les opérations CRUD
- CoachService interface avec toutes les opérations CRUD
- ClientServiceImpl avec simulation complète
- CoachServiceImpl avec simulation complète

📊 DTOs COMPLETS :
- ClientDTO, CreateClientDTO, UpdateClientDTO
- CoachDTO, CreateCoachDTO, UpdateCoachDTO
- PagedResponseDTO générique pour pagination

🌐 REST CONTROLLERS :
- ClientResource avec endpoints CRUD complets
- CoachResource avec endpoints CRUD complets
- Sécurité basée sur les rôles (@RolesAllowed)
- Documentation OpenAPI complète

🧪 TESTS UNITAIRES EXHAUSTIFS :
- PasswordServiceTest (25 tests)
- EmailServiceSimpleTest (20 tests)
- BaseEntityTest (15 tests)
- ClientEntityTest (20 tests)
- CoachEntityTest (25 tests)

🎯 FONCTIONNALITÉS MÉTIER :
- Gestion complète du cycle de vie des clients
- Conversion prospect → client
- Gestion des coaches avec disponibilités
- Système de notation des coaches
- Filtrage et recherche avancée
- Pagination et tri

📈 COUVERTURE DE TESTS :
- 105+ nouveaux tests unitaires créés
- Couverture fonctionnelle complète des services
- Tests d'entités avec validation complète
- Tests de performance inclus

🔒 SÉCURITÉ ET VALIDATION :
- Validation Jakarta sur tous les DTOs
- Gestion d'erreurs robuste avec GBCMException
- Logging SLF4J détaillé
- Mode simulation pour développement

Cette phase ajoute les fonctionnalités core de gestion des clients et coaches,
établissant une base solide pour l'application GBCM complète.
2025-10-07 10:15:58 +00:00

310 lines
13 KiB
Java

package com.gbcm.server.impl.resource;
import com.gbcm.server.api.dto.client.ClientDTO;
import com.gbcm.server.api.dto.client.CreateClientDTO;
import com.gbcm.server.api.dto.client.UpdateClientDTO;
import com.gbcm.server.api.dto.common.PagedResponseDTO;
import com.gbcm.server.api.enums.ServiceType;
import com.gbcm.server.api.exception.GBCMException;
import com.gbcm.server.api.service.ClientService;
import com.gbcm.server.impl.entity.Client.ClientStatus;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
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.Parameter;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Contrôleur REST pour la gestion des clients de la plateforme GBCM.
* Expose tous les endpoints CRUD pour les clients avec sécurité basée sur les rôles.
*
* @author GBCM Development Team
* @version 1.0
* @since 1.0
*/
@Path("/api/clients")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Clients", description = "Gestion des clients GBCM")
public class ClientResource {
private static final Logger logger = LoggerFactory.getLogger(ClientResource.class);
@Inject
ClientService clientService;
/**
* Endpoint pour récupérer la liste paginée des clients.
*
* @param page numéro de page (commence à 0)
* @param size taille de page
* @param sort critères de tri
* @param status filtre par statut
* @param industry filtre par secteur d'activité
* @param search terme de recherche
* @return liste paginée des clients
*/
@GET
@RolesAllowed({"ADMIN", "MANAGER", "COACH"})
@Operation(
summary = "Liste des clients",
description = "Récupère la liste paginée des clients avec filtres optionnels"
)
@APIResponses({
@APIResponse(
responseCode = "200",
description = "Liste récupérée avec succès",
content = @Content(schema = @Schema(implementation = PagedResponseDTO.class))
),
@APIResponse(responseCode = "401", description = "Non authentifié"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Response getClients(
@Parameter(description = "Numéro de page (commence à 0)", example = "0")
@QueryParam("page") @DefaultValue("0") int page,
@Parameter(description = "Taille de page", example = "20")
@QueryParam("size") @DefaultValue("20") int size,
@Parameter(description = "Tri (ex: companyName,asc ou convertedAt,desc)")
@QueryParam("sort") String sort,
@Parameter(description = "Filtre par statut")
@QueryParam("status") ClientStatus status,
@Parameter(description = "Filtre par secteur d'activité")
@QueryParam("industry") String industry,
@Parameter(description = "Terme de recherche (nom entreprise, email)")
@QueryParam("search") String search
) {
try {
logger.info("Récupération de la liste des clients - page: {}, size: {}", page, size);
PagedResponseDTO<ClientDTO> clients = clientService.getClients(page, size, sort, status, industry, search);
logger.info("Liste des clients récupérée avec succès - {} éléments", clients.getTotalElements());
return Response.ok(clients).build();
} catch (GBCMException e) {
logger.error("Erreur GBCM lors de la récupération des clients: {}", e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("Erreur: " + e.getMessage())
.build();
} catch (Exception e) {
logger.error("Erreur inattendue lors de la récupération des clients: {}", e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur interne du serveur")
.build();
}
}
/**
* Endpoint pour récupérer un client par son ID.
*
* @param id l'identifiant du client
* @return le client trouvé
*/
@GET
@Path("/{id}")
@RolesAllowed({"ADMIN", "MANAGER", "COACH", "CLIENT"})
@Operation(
summary = "Récupérer un client",
description = "Récupère un client par son identifiant"
)
@APIResponses({
@APIResponse(
responseCode = "200",
description = "Client trouvé",
content = @Content(schema = @Schema(implementation = ClientDTO.class))
),
@APIResponse(responseCode = "401", description = "Non authentifié"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "Client non trouvé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Response getClientById(
@Parameter(description = "Identifiant du client", required = true)
@PathParam("id") Long id
) {
try {
logger.info("Récupération du client avec l'ID: {}", id);
ClientDTO client = clientService.getClientById(id);
logger.info("Client récupéré avec succès: {}", client.getCompanyName());
return Response.ok(client).build();
} catch (GBCMException e) {
logger.warn("Client non trouvé avec l'ID {}: {}", id, e.getMessage());
return Response.status(Response.Status.NOT_FOUND)
.entity("Client non trouvé: " + e.getMessage())
.build();
} catch (Exception e) {
logger.error("Erreur inattendue lors de la récupération du client {}: {}", id, e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur interne du serveur")
.build();
}
}
/**
* Endpoint pour créer un nouveau client.
*
* @param createClientDTO les données du nouveau client
* @return le client créé
*/
@POST
@RolesAllowed({"ADMIN", "MANAGER"})
@Operation(
summary = "Créer un client",
description = "Crée un nouveau client dans le système"
)
@APIResponses({
@APIResponse(
responseCode = "201",
description = "Client créé avec succès",
content = @Content(schema = @Schema(implementation = ClientDTO.class))
),
@APIResponse(responseCode = "400", description = "Données invalides"),
@APIResponse(responseCode = "401", description = "Non authentifié"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "409", description = "Client déjà existant"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Response createClient(
@Parameter(description = "Données du nouveau client", required = true)
@Valid CreateClientDTO createClientDTO
) {
try {
logger.info("Création d'un nouveau client: {}", createClientDTO.getCompanyName());
ClientDTO client = clientService.createClient(createClientDTO);
logger.info("Client créé avec succès avec l'ID: {}", client.getId());
return Response.status(Response.Status.CREATED).entity(client).build();
} catch (GBCMException e) {
logger.error("Erreur GBCM lors de la création du client: {}", e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("Erreur: " + e.getMessage())
.build();
} catch (Exception e) {
logger.error("Erreur inattendue lors de la création du client: {}", e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur interne du serveur")
.build();
}
}
/**
* Endpoint pour mettre à jour un client existant.
*
* @param id l'identifiant du client
* @param updateClientDTO les données de mise à jour
* @return le client mis à jour
*/
@PUT
@Path("/{id}")
@RolesAllowed({"ADMIN", "MANAGER", "CLIENT"})
@Operation(
summary = "Mettre à jour un client",
description = "Met à jour les informations d'un client existant"
)
@APIResponses({
@APIResponse(
responseCode = "200",
description = "Client mis à jour avec succès",
content = @Content(schema = @Schema(implementation = ClientDTO.class))
),
@APIResponse(responseCode = "400", description = "Données invalides"),
@APIResponse(responseCode = "401", description = "Non authentifié"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "Client non trouvé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Response updateClient(
@Parameter(description = "Identifiant du client", required = true)
@PathParam("id") Long id,
@Parameter(description = "Données de mise à jour", required = true)
@Valid UpdateClientDTO updateClientDTO
) {
try {
logger.info("Mise à jour du client avec l'ID: {}", id);
ClientDTO client = clientService.updateClient(id, updateClientDTO);
logger.info("Client mis à jour avec succès: {}", client.getCompanyName());
return Response.ok(client).build();
} catch (GBCMException e) {
logger.error("Erreur GBCM lors de la mise à jour du client {}: {}", id, e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("Erreur: " + e.getMessage())
.build();
} catch (Exception e) {
logger.error("Erreur inattendue lors de la mise à jour du client {}: {}", id, e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur interne du serveur")
.build();
}
}
/**
* Endpoint pour supprimer un client (soft delete).
*
* @param id l'identifiant du client
* @return confirmation de suppression
*/
@DELETE
@Path("/{id}")
@RolesAllowed({"ADMIN"})
@Operation(
summary = "Supprimer un client",
description = "Supprime un client du système (suppression logique)"
)
@APIResponses({
@APIResponse(responseCode = "204", description = "Client supprimé avec succès"),
@APIResponse(responseCode = "401", description = "Non authentifié"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "Client non trouvé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Response deleteClient(
@Parameter(description = "Identifiant du client", required = true)
@PathParam("id") Long id
) {
try {
logger.info("Suppression du client avec l'ID: {}", id);
clientService.deleteClient(id);
logger.info("Client supprimé avec succès: {}", id);
return Response.noContent().build();
} catch (GBCMException e) {
logger.error("Erreur GBCM lors de la suppression du client {}: {}", id, e.getMessage());
return Response.status(Response.Status.NOT_FOUND)
.entity("Client non trouvé: " + e.getMessage())
.build();
} catch (Exception e) {
logger.error("Erreur inattendue lors de la suppression du client {}: {}", id, e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur interne du serveur")
.build();
}
}
}