Initial commit
This commit is contained in:
@@ -0,0 +1,366 @@
|
||||
package dev.lions.btpxpress.adapter.http;
|
||||
|
||||
import dev.lions.btpxpress.application.service.ChantierService;
|
||||
import dev.lions.btpxpress.domain.core.entity.Chantier;
|
||||
import dev.lions.btpxpress.domain.core.entity.StatutChantier;
|
||||
import dev.lions.btpxpress.domain.shared.dto.ChantierCreateDTO;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Resource REST pour la gestion des chantiers - Architecture 2025 MIGRATION: Préservation exacte de
|
||||
* tous les endpoints critiques
|
||||
*/
|
||||
@Path("/api/v1/chantiers")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Tag(name = "Chantiers", description = "Gestion des chantiers BTP")
|
||||
// @Authenticated - Désactivé pour les tests
|
||||
public class ChantierResource {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ChantierResource.class);
|
||||
|
||||
@Inject ChantierService chantierService;
|
||||
|
||||
// === ENDPOINTS DE CONSULTATION - API CONTRACTS PRÉSERVÉS EXACTEMENT ===
|
||||
|
||||
@GET
|
||||
@Operation(summary = "Récupérer tous les chantiers")
|
||||
@APIResponse(responseCode = "200", description = "Liste des chantiers récupérée avec succès")
|
||||
public Response getAllChantiers(
|
||||
@Parameter(description = "Terme de recherche") @QueryParam("search") String search,
|
||||
@Parameter(description = "Statut du chantier") @QueryParam("statut") String statut,
|
||||
@Parameter(description = "ID du client") @QueryParam("clientId") String clientId) {
|
||||
try {
|
||||
List<Chantier> chantiers;
|
||||
|
||||
if (clientId != null && !clientId.isEmpty()) {
|
||||
chantiers = chantierService.findByClient(UUID.fromString(clientId));
|
||||
} else if (statut != null && !statut.isEmpty()) {
|
||||
chantiers = chantierService.findByStatut(StatutChantier.valueOf(statut.toUpperCase()));
|
||||
} else if (search != null && !search.isEmpty()) {
|
||||
chantiers = chantierService.search(search);
|
||||
} else {
|
||||
chantiers = chantierService.findAll();
|
||||
}
|
||||
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/actifs")
|
||||
@Operation(summary = "Récupérer tous les chantiers actifs")
|
||||
@APIResponse(
|
||||
responseCode = "200",
|
||||
description = "Liste des chantiers actifs récupérée avec succès")
|
||||
public Response getAllActiveChantiers() {
|
||||
try {
|
||||
List<Chantier> chantiers = chantierService.findAllActive();
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers actifs", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers actifs: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Récupérer un chantier par ID")
|
||||
@APIResponse(responseCode = "200", description = "Chantier récupéré avec succès")
|
||||
@APIResponse(responseCode = "404", description = "Chantier non trouvé")
|
||||
public Response getChantierById(
|
||||
@Parameter(description = "ID du chantier") @PathParam("id") String id) {
|
||||
try {
|
||||
UUID chantierId = UUID.fromString(id);
|
||||
return chantierService
|
||||
.findById(chantierId)
|
||||
.map(chantier -> Response.ok(chantier).build())
|
||||
.orElse(
|
||||
Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("Chantier non trouvé avec l'ID: " + id)
|
||||
.build());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("ID de chantier invalide: " + id)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération du chantier {}", id, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération du chantier: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/count")
|
||||
@Operation(summary = "Compter le nombre de chantiers")
|
||||
@APIResponse(responseCode = "200", description = "Nombre de chantiers récupéré avec succès")
|
||||
public Response countChantiers() {
|
||||
try {
|
||||
long count = chantierService.count();
|
||||
return Response.ok(new CountResponse(count)).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors du comptage des chantiers", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors du comptage des chantiers: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/stats")
|
||||
@Operation(summary = "Obtenir les statistiques des chantiers")
|
||||
@APIResponse(responseCode = "200", description = "Statistiques récupérées avec succès")
|
||||
public Response getStats() {
|
||||
try {
|
||||
Object stats = chantierService.getStatistics();
|
||||
return Response.ok(stats).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la génération des statistiques des chantiers", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la génération des statistiques: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/statut/{statut}")
|
||||
public Response getChantiersByStatut(@PathParam("statut") String statut) {
|
||||
try {
|
||||
StatutChantier statutEnum = StatutChantier.valueOf(statut.toUpperCase());
|
||||
List<Chantier> chantiers = chantierService.findByStatut(statutEnum);
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(
|
||||
"Statut invalide: "
|
||||
+ statut
|
||||
+ ". Valeurs possibles: PLANIFIE, EN_COURS, TERMINE, ANNULE, SUSPENDU")
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers par statut {}", statut, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/en-cours")
|
||||
public Response getChantiersEnCours() {
|
||||
try {
|
||||
List<Chantier> chantiers = chantierService.findEnCours();
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers en cours", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers en cours: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/planifies")
|
||||
public Response getChantiersPlanifies() {
|
||||
try {
|
||||
List<Chantier> chantiers = chantierService.findPlanifies();
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers planifiés", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers planifiés: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/termines")
|
||||
public Response getChantiersTermines() {
|
||||
try {
|
||||
List<Chantier> chantiers = chantierService.findTermines();
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la récupération des chantiers terminés", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la récupération des chantiers terminés: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// === ENDPOINTS DE GESTION - API CONTRACTS PRÉSERVÉS EXACTEMENT ===
|
||||
|
||||
@POST
|
||||
@Operation(summary = "Créer un nouveau chantier")
|
||||
@APIResponse(responseCode = "201", description = "Chantier créé avec succès")
|
||||
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||
public Response createChantier(
|
||||
@Parameter(description = "Données du chantier à créer") @Valid @NotNull
|
||||
ChantierCreateDTO chantierDTO) {
|
||||
try {
|
||||
Chantier chantier = chantierService.create(chantierDTO);
|
||||
return Response.status(Response.Status.CREATED).entity(chantier).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Données invalides: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la création du chantier", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la création du chantier: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Mettre à jour un chantier")
|
||||
@APIResponse(responseCode = "200", description = "Chantier mis à jour avec succès")
|
||||
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||
@APIResponse(responseCode = "404", description = "Chantier non trouvé")
|
||||
public Response updateChantier(
|
||||
@Parameter(description = "ID du chantier") @PathParam("id") String id,
|
||||
@Parameter(description = "Nouvelles données du chantier") @Valid @NotNull
|
||||
ChantierCreateDTO chantierDTO) {
|
||||
try {
|
||||
UUID chantierId = UUID.fromString(id);
|
||||
Chantier chantier = chantierService.update(chantierId, chantierDTO);
|
||||
return Response.ok(chantier).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Données invalides: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la mise à jour du chantier {}", id, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la mise à jour du chantier: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{id}/statut")
|
||||
public Response updateChantierStatut(@PathParam("id") String id, UpdateStatutRequest request) {
|
||||
try {
|
||||
UUID chantierId = UUID.fromString(id);
|
||||
StatutChantier nouveauStatut = StatutChantier.valueOf(request.statut.toUpperCase());
|
||||
Chantier chantier = chantierService.updateStatut(chantierId, nouveauStatut);
|
||||
return Response.ok(chantier).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Données invalides: " + e.getMessage())
|
||||
.build();
|
||||
} catch (IllegalStateException e) {
|
||||
return Response.status(Response.Status.CONFLICT)
|
||||
.entity("Transition de statut non autorisée: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la mise à jour du statut du chantier {}", id, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la mise à jour du statut: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Supprimer un chantier")
|
||||
@APIResponse(responseCode = "204", description = "Chantier supprimé avec succès")
|
||||
@APIResponse(responseCode = "400", description = "ID invalide")
|
||||
@APIResponse(responseCode = "404", description = "Chantier non trouvé")
|
||||
@APIResponse(responseCode = "409", description = "Impossible de supprimer")
|
||||
public Response deleteChantier(
|
||||
@Parameter(description = "ID du chantier") @PathParam("id") String id,
|
||||
@Parameter(description = "Suppression définitive (true) ou logique (false, défaut)")
|
||||
@QueryParam("permanent")
|
||||
@DefaultValue("false")
|
||||
boolean permanent) {
|
||||
try {
|
||||
UUID chantierId = UUID.fromString(id);
|
||||
|
||||
if (permanent) {
|
||||
chantierService.deletePhysically(chantierId);
|
||||
} else {
|
||||
chantierService.delete(chantierId);
|
||||
}
|
||||
|
||||
return Response.noContent().build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("ID invalide: " + e.getMessage())
|
||||
.build();
|
||||
} catch (IllegalStateException e) {
|
||||
return Response.status(Response.Status.CONFLICT)
|
||||
.entity("Impossible de supprimer: " + e.getMessage())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la suppression du chantier {}", id, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la suppression du chantier: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
// ENDPOINTS DE RECHERCHE AVANCÉE
|
||||
// ===========================================
|
||||
|
||||
@GET
|
||||
@Path("/date-range")
|
||||
public Response getChantiersByDateRange(
|
||||
@QueryParam("dateDebut") String dateDebut, @QueryParam("dateFin") String dateFin) {
|
||||
try {
|
||||
if (dateDebut == null || dateFin == null) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("Les paramètres dateDebut et dateFin sont obligatoires")
|
||||
.build();
|
||||
}
|
||||
|
||||
LocalDate debut = LocalDate.parse(dateDebut);
|
||||
LocalDate fin = LocalDate.parse(dateFin);
|
||||
|
||||
if (debut.isAfter(fin)) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("La date de début ne peut pas être après la date de fin")
|
||||
.build();
|
||||
}
|
||||
|
||||
List<Chantier> chantiers = chantierService.findByDateRange(debut, fin);
|
||||
return Response.ok(chantiers).build();
|
||||
} catch (Exception e) {
|
||||
logger.error("Erreur lors de la recherche par plage de dates", e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Erreur lors de la recherche: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================
|
||||
// CLASSES UTILITAIRES
|
||||
// ===========================================
|
||||
|
||||
public static record CountResponse(long count) {}
|
||||
|
||||
public static record UpdateStatutRequest(String statut) {}
|
||||
}
|
||||
Reference in New Issue
Block a user