Configure Maven repository for unionflow-server-api dependency
This commit is contained in:
@@ -0,0 +1,643 @@
|
||||
package dev.lions.unionflow.server.resource;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreDTO;
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchCriteria;
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchResultDTO;
|
||||
import dev.lions.unionflow.server.entity.Membre;
|
||||
import dev.lions.unionflow.server.service.MembreService;
|
||||
import io.quarkus.panache.common.Page;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
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 java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Content;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
|
||||
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/** Resource REST pour la gestion des membres */
|
||||
@Path("/api/membres")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ApplicationScoped
|
||||
@Tag(name = "Membres", description = "API de gestion des membres")
|
||||
public class MembreResource {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(MembreResource.class);
|
||||
|
||||
@Inject MembreService membreService;
|
||||
|
||||
@GET
|
||||
@Operation(summary = "Lister tous les membres actifs")
|
||||
@APIResponse(responseCode = "200", description = "Liste des membres actifs")
|
||||
public Response listerMembres(
|
||||
@Parameter(description = "Numéro de page (0-based)") @QueryParam("page") @DefaultValue("0")
|
||||
int page,
|
||||
@Parameter(description = "Taille de la page") @QueryParam("size") @DefaultValue("20")
|
||||
int size,
|
||||
@Parameter(description = "Champ de tri") @QueryParam("sort") @DefaultValue("nom")
|
||||
String sortField,
|
||||
@Parameter(description = "Direction du tri (asc/desc)")
|
||||
@QueryParam("direction")
|
||||
@DefaultValue("asc")
|
||||
String sortDirection) {
|
||||
|
||||
LOG.infof("Récupération de la liste des membres actifs - page: %d, size: %d", page, size);
|
||||
|
||||
Sort sort =
|
||||
"desc".equalsIgnoreCase(sortDirection)
|
||||
? Sort.by(sortField).descending()
|
||||
: Sort.by(sortField).ascending();
|
||||
|
||||
List<Membre> membres = membreService.listerMembresActifs(Page.of(page, size), sort);
|
||||
List<MembreDTO> membresDTO = membreService.convertToDTOList(membres);
|
||||
|
||||
return Response.ok(membresDTO).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Récupérer un membre par son ID")
|
||||
@APIResponse(responseCode = "200", description = "Membre trouvé")
|
||||
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||
public Response obtenirMembre(@Parameter(description = "UUID du membre") @PathParam("id") UUID id) {
|
||||
LOG.infof("Récupération du membre ID: %s", id);
|
||||
return membreService
|
||||
.trouverParId(id)
|
||||
.map(
|
||||
membre -> {
|
||||
MembreDTO membreDTO = membreService.convertToDTO(membre);
|
||||
return Response.ok(membreDTO).build();
|
||||
})
|
||||
.orElse(
|
||||
Response.status(Response.Status.NOT_FOUND)
|
||||
.entity(Map.of("message", "Membre non trouvé"))
|
||||
.build());
|
||||
}
|
||||
|
||||
@POST
|
||||
@PermitAll
|
||||
@Operation(summary = "Créer un nouveau membre")
|
||||
@APIResponse(responseCode = "201", description = "Membre créé avec succès")
|
||||
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||
public Response creerMembre(@Valid MembreDTO membreDTO) {
|
||||
LOG.infof("Création d'un nouveau membre: %s", membreDTO.getEmail());
|
||||
try {
|
||||
// Conversion DTO vers entité
|
||||
Membre membre = membreService.convertFromDTO(membreDTO);
|
||||
|
||||
// Création du membre
|
||||
Membre nouveauMembre = membreService.creerMembre(membre);
|
||||
|
||||
// Conversion de retour vers DTO
|
||||
MembreDTO nouveauMembreDTO = membreService.convertToDTO(nouveauMembre);
|
||||
|
||||
return Response.status(Response.Status.CREATED).entity(nouveauMembreDTO).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Mettre à jour un membre existant")
|
||||
@APIResponse(responseCode = "200", description = "Membre mis à jour avec succès")
|
||||
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||
@APIResponse(responseCode = "400", description = "Données invalides")
|
||||
public Response mettreAJourMembre(
|
||||
@Parameter(description = "UUID du membre") @PathParam("id") UUID id,
|
||||
@Valid MembreDTO membreDTO) {
|
||||
LOG.infof("Mise à jour du membre ID: %s", id);
|
||||
try {
|
||||
// Conversion DTO vers entité
|
||||
Membre membre = membreService.convertFromDTO(membreDTO);
|
||||
|
||||
// Mise à jour du membre
|
||||
Membre membreMisAJour = membreService.mettreAJourMembre(id, membre);
|
||||
|
||||
// Conversion de retour vers DTO
|
||||
MembreDTO membreMisAJourDTO = membreService.convertToDTO(membreMisAJour);
|
||||
|
||||
return Response.ok(membreMisAJourDTO).build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@Operation(summary = "Désactiver un membre")
|
||||
@APIResponse(responseCode = "204", description = "Membre désactivé avec succès")
|
||||
@APIResponse(responseCode = "404", description = "Membre non trouvé")
|
||||
public Response desactiverMembre(
|
||||
@Parameter(description = "UUID du membre") @PathParam("id") UUID id) {
|
||||
LOG.infof("Désactivation du membre ID: %s", id);
|
||||
try {
|
||||
membreService.desactiverMembre(id);
|
||||
return Response.noContent().build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity(Map.of("message", e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/recherche")
|
||||
@Operation(summary = "Rechercher des membres par nom ou prénom")
|
||||
@APIResponse(responseCode = "200", description = "Résultats de la recherche")
|
||||
public Response rechercherMembres(
|
||||
@Parameter(description = "Terme de recherche") @QueryParam("q") String recherche,
|
||||
@Parameter(description = "Numéro de page (0-based)") @QueryParam("page") @DefaultValue("0")
|
||||
int page,
|
||||
@Parameter(description = "Taille de la page") @QueryParam("size") @DefaultValue("20")
|
||||
int size,
|
||||
@Parameter(description = "Champ de tri") @QueryParam("sort") @DefaultValue("nom")
|
||||
String sortField,
|
||||
@Parameter(description = "Direction du tri (asc/desc)")
|
||||
@QueryParam("direction")
|
||||
@DefaultValue("asc")
|
||||
String sortDirection) {
|
||||
|
||||
LOG.infof("Recherche de membres avec le terme: %s", recherche);
|
||||
if (recherche == null || recherche.trim().isEmpty()) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Le terme de recherche est requis"))
|
||||
.build();
|
||||
}
|
||||
|
||||
Sort sort =
|
||||
"desc".equalsIgnoreCase(sortDirection)
|
||||
? Sort.by(sortField).descending()
|
||||
: Sort.by(sortField).ascending();
|
||||
|
||||
List<Membre> membres =
|
||||
membreService.rechercherMembres(recherche.trim(), Page.of(page, size), sort);
|
||||
List<MembreDTO> membresDTO = membreService.convertToDTOList(membres);
|
||||
|
||||
return Response.ok(membresDTO).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/stats")
|
||||
@Operation(summary = "Obtenir les statistiques avancées des membres")
|
||||
@APIResponse(responseCode = "200", description = "Statistiques complètes des membres")
|
||||
public Response obtenirStatistiques() {
|
||||
LOG.info("Récupération des statistiques avancées des membres");
|
||||
Map<String, Object> statistiques = membreService.obtenirStatistiquesAvancees();
|
||||
return Response.ok(statistiques).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/autocomplete/villes")
|
||||
@Operation(summary = "Obtenir la liste des villes pour autocomplétion")
|
||||
@APIResponse(responseCode = "200", description = "Liste des villes distinctes")
|
||||
public Response obtenirVilles(
|
||||
@Parameter(description = "Terme de recherche (optionnel)") @QueryParam("query") String query) {
|
||||
LOG.infof("Récupération des villes pour autocomplétion - query: %s", query);
|
||||
List<String> villes = membreService.obtenirVillesDistinctes(query);
|
||||
return Response.ok(villes).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/autocomplete/professions")
|
||||
@Operation(summary = "Obtenir la liste des professions pour autocomplétion")
|
||||
@APIResponse(responseCode = "200", description = "Liste des professions distinctes")
|
||||
public Response obtenirProfessions(
|
||||
@Parameter(description = "Terme de recherche (optionnel)") @QueryParam("query") String query) {
|
||||
LOG.infof("Récupération des professions pour autocomplétion - query: %s", query);
|
||||
List<String> professions = membreService.obtenirProfessionsDistinctes(query);
|
||||
return Response.ok(professions).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/recherche-avancee")
|
||||
@Operation(summary = "Recherche avancée de membres avec filtres multiples (DEPRECATED)")
|
||||
@APIResponse(responseCode = "200", description = "Résultats de la recherche avancée")
|
||||
@Deprecated
|
||||
public Response rechercheAvancee(
|
||||
@Parameter(description = "Terme de recherche") @QueryParam("q") String recherche,
|
||||
@Parameter(description = "Statut actif (true/false)") @QueryParam("actif") Boolean actif,
|
||||
@Parameter(description = "Date d'adhésion minimum (YYYY-MM-DD)")
|
||||
@QueryParam("dateAdhesionMin")
|
||||
String dateAdhesionMin,
|
||||
@Parameter(description = "Date d'adhésion maximum (YYYY-MM-DD)")
|
||||
@QueryParam("dateAdhesionMax")
|
||||
String dateAdhesionMax,
|
||||
@Parameter(description = "Numéro de page (0-based)") @QueryParam("page") @DefaultValue("0")
|
||||
int page,
|
||||
@Parameter(description = "Taille de la page") @QueryParam("size") @DefaultValue("20")
|
||||
int size,
|
||||
@Parameter(description = "Champ de tri") @QueryParam("sort") @DefaultValue("nom")
|
||||
String sortField,
|
||||
@Parameter(description = "Direction du tri (asc/desc)")
|
||||
@QueryParam("direction")
|
||||
@DefaultValue("asc")
|
||||
String sortDirection) {
|
||||
|
||||
LOG.infof(
|
||||
"Recherche avancée de membres (DEPRECATED) - recherche: %s, actif: %s", recherche, actif);
|
||||
|
||||
try {
|
||||
Sort sort =
|
||||
"desc".equalsIgnoreCase(sortDirection)
|
||||
? Sort.by(sortField).descending()
|
||||
: Sort.by(sortField).ascending();
|
||||
|
||||
// Conversion des dates si fournies
|
||||
java.time.LocalDate dateMin =
|
||||
dateAdhesionMin != null ? java.time.LocalDate.parse(dateAdhesionMin) : null;
|
||||
java.time.LocalDate dateMax =
|
||||
dateAdhesionMax != null ? java.time.LocalDate.parse(dateAdhesionMax) : null;
|
||||
|
||||
List<Membre> membres =
|
||||
membreService.rechercheAvancee(
|
||||
recherche, actif, dateMin, dateMax, Page.of(page, size), sort);
|
||||
List<MembreDTO> membresDTO = membreService.convertToDTOList(membres);
|
||||
|
||||
return Response.ok(membresDTO).build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf("Erreur lors de la recherche avancée: %s", e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Erreur dans les paramètres de recherche: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nouvelle recherche avancée avec critères complets et résultats enrichis Réservée aux super
|
||||
* administrateurs pour des recherches sophistiquées
|
||||
*/
|
||||
@POST
|
||||
@Path("/search/advanced")
|
||||
@RolesAllowed({"SUPER_ADMIN", "ADMIN"})
|
||||
@Operation(
|
||||
summary = "Recherche avancée de membres avec critères multiples",
|
||||
description =
|
||||
"""
|
||||
Recherche sophistiquée de membres avec de nombreux critères de filtrage :
|
||||
- Recherche textuelle dans nom, prénom, email
|
||||
- Filtres par organisation, rôles, statut
|
||||
- Filtres par âge, région, profession
|
||||
- Filtres par dates d'adhésion
|
||||
- Résultats paginés avec statistiques
|
||||
|
||||
Réservée aux super administrateurs et administrateurs.
|
||||
""")
|
||||
@APIResponses({
|
||||
@APIResponse(
|
||||
responseCode = "200",
|
||||
description = "Recherche effectuée avec succès",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(implementation = MembreSearchResultDTO.class),
|
||||
examples =
|
||||
@ExampleObject(
|
||||
name = "Exemple de résultats",
|
||||
value =
|
||||
"""
|
||||
{
|
||||
"membres": [...],
|
||||
"totalElements": 247,
|
||||
"totalPages": 13,
|
||||
"currentPage": 0,
|
||||
"pageSize": 20,
|
||||
"hasNext": true,
|
||||
"hasPrevious": false,
|
||||
"executionTimeMs": 45,
|
||||
"statistics": {
|
||||
"membresActifs": 230,
|
||||
"membresInactifs": 17,
|
||||
"ageMoyen": 34.5,
|
||||
"nombreOrganisations": 12
|
||||
}
|
||||
}
|
||||
"""))),
|
||||
@APIResponse(
|
||||
responseCode = "400",
|
||||
description = "Critères de recherche invalides",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
examples =
|
||||
@ExampleObject(
|
||||
value =
|
||||
"""
|
||||
{
|
||||
"message": "Critères de recherche invalides",
|
||||
"details": "La date minimum ne peut pas être postérieure à la date maximum"
|
||||
}
|
||||
"""))),
|
||||
@APIResponse(
|
||||
responseCode = "403",
|
||||
description = "Accès non autorisé - Rôle SUPER_ADMIN ou ADMIN requis"),
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
@SecurityRequirement(name = "keycloak")
|
||||
public Response searchMembresAdvanced(
|
||||
@RequestBody(
|
||||
description = "Critères de recherche avancée",
|
||||
required = false,
|
||||
content =
|
||||
@Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(implementation = MembreSearchCriteria.class),
|
||||
examples =
|
||||
@ExampleObject(
|
||||
name = "Exemple de critères",
|
||||
value =
|
||||
"""
|
||||
{
|
||||
"query": "marie",
|
||||
"statut": "ACTIF",
|
||||
"ageMin": 25,
|
||||
"ageMax": 45,
|
||||
"region": "Dakar",
|
||||
"roles": ["PRESIDENT", "SECRETAIRE"],
|
||||
"dateAdhesionMin": "2020-01-01",
|
||||
"includeInactifs": false
|
||||
}
|
||||
""")))
|
||||
MembreSearchCriteria criteria,
|
||||
@Parameter(description = "Numéro de page (0-based)", example = "0")
|
||||
@QueryParam("page")
|
||||
@DefaultValue("0")
|
||||
int page,
|
||||
@Parameter(description = "Taille de la page", example = "20")
|
||||
@QueryParam("size")
|
||||
@DefaultValue("20")
|
||||
int size,
|
||||
@Parameter(description = "Champ de tri", example = "nom")
|
||||
@QueryParam("sort")
|
||||
@DefaultValue("nom")
|
||||
String sortField,
|
||||
@Parameter(description = "Direction du tri (asc/desc)", example = "asc")
|
||||
@QueryParam("direction")
|
||||
@DefaultValue("asc")
|
||||
String sortDirection) {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// Validation des critères
|
||||
if (criteria == null) {
|
||||
LOG.warn("Recherche avancée de membres - critères null rejetés");
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Les critères de recherche sont requis"))
|
||||
.build();
|
||||
}
|
||||
|
||||
LOG.infof(
|
||||
"Recherche avancée de membres - critères: %s, page: %d, size: %d",
|
||||
criteria.getDescription(), page, size);
|
||||
|
||||
// Nettoyage et validation des critères
|
||||
criteria.sanitize();
|
||||
|
||||
if (!criteria.hasAnyCriteria()) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Au moins un critère de recherche doit être spécifié"))
|
||||
.build();
|
||||
}
|
||||
|
||||
if (!criteria.isValid()) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(
|
||||
Map.of(
|
||||
"message", "Critères de recherche invalides",
|
||||
"details", "Vérifiez la cohérence des dates et des âges"))
|
||||
.build();
|
||||
}
|
||||
|
||||
// Construction du tri
|
||||
Sort sort =
|
||||
"desc".equalsIgnoreCase(sortDirection)
|
||||
? Sort.by(sortField).descending()
|
||||
: Sort.by(sortField).ascending();
|
||||
|
||||
// Exécution de la recherche
|
||||
MembreSearchResultDTO result =
|
||||
membreService.searchMembresAdvanced(criteria, Page.of(page, size), sort);
|
||||
|
||||
// Calcul du temps d'exécution
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
result.setExecutionTimeMs(executionTime);
|
||||
|
||||
LOG.infof(
|
||||
"Recherche avancée terminée - %d résultats trouvés en %d ms",
|
||||
result.getTotalElements(), executionTime);
|
||||
|
||||
return Response.ok(result).build();
|
||||
|
||||
} catch (jakarta.validation.ConstraintViolationException e) {
|
||||
LOG.warnf("Erreur de validation Jakarta dans la recherche avancée: %s", e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Critères de recherche invalides", "details", e.getMessage()))
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warnf("Erreur de validation dans la recherche avancée: %s", e.getMessage());
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("message", "Paramètres de recherche invalides", "details", e.getMessage()))
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de la recherche avancée de membres");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("message", "Erreur interne lors de la recherche", "error", e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/export/selection")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
@Operation(summary = "Exporter une sélection de membres en Excel")
|
||||
@APIResponse(responseCode = "200", description = "Fichier Excel généré")
|
||||
public Response exporterSelectionMembres(
|
||||
@Parameter(description = "Liste des IDs des membres à exporter") List<UUID> membreIds,
|
||||
@Parameter(description = "Format d'export") @QueryParam("format") @DefaultValue("EXCEL") String format) {
|
||||
LOG.infof("Export de %d membres sélectionnés", membreIds.size());
|
||||
try {
|
||||
byte[] excelData = membreService.exporterMembresSelectionnes(membreIds, format);
|
||||
return Response.ok(excelData)
|
||||
.header("Content-Disposition", "attachment; filename=\"membres_selection_" +
|
||||
java.time.LocalDate.now() + "." + (format != null ? format.toLowerCase() : "xlsx") + "\"")
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'export de la sélection");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("error", "Erreur lors de l'export: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/import")
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Importer des membres depuis un fichier Excel ou CSV")
|
||||
@APIResponse(responseCode = "200", description = "Import terminé")
|
||||
public Response importerMembres(
|
||||
@Parameter(description = "Contenu du fichier à importer") @FormParam("file") byte[] fileContent,
|
||||
@Parameter(description = "Nom du fichier") @FormParam("fileName") String fileName,
|
||||
@Parameter(description = "ID de l'organisation (optionnel)") @FormParam("organisationId") UUID organisationId,
|
||||
@Parameter(description = "Type de membre par défaut") @FormParam("typeMembreDefaut") String typeMembreDefaut,
|
||||
@Parameter(description = "Mettre à jour les membres existants") @FormParam("mettreAJourExistants") boolean mettreAJourExistants,
|
||||
@Parameter(description = "Ignorer les erreurs") @FormParam("ignorerErreurs") boolean ignorerErreurs) {
|
||||
|
||||
try {
|
||||
if (fileContent == null || fileContent.length == 0) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("error", "Aucun fichier fourni"))
|
||||
.build();
|
||||
}
|
||||
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
fileName = "import.xlsx";
|
||||
}
|
||||
|
||||
if (typeMembreDefaut == null || typeMembreDefaut.isEmpty()) {
|
||||
typeMembreDefaut = "ACTIF";
|
||||
}
|
||||
|
||||
InputStream fileInputStream = new java.io.ByteArrayInputStream(fileContent);
|
||||
dev.lions.unionflow.server.service.MembreImportExportService.ResultatImport resultat = membreService.importerMembres(
|
||||
fileInputStream, fileName, organisationId, typeMembreDefaut, mettreAJourExistants, ignorerErreurs);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("totalLignes", resultat.totalLignes);
|
||||
response.put("lignesTraitees", resultat.lignesTraitees);
|
||||
response.put("lignesErreur", resultat.lignesErreur);
|
||||
response.put("erreurs", resultat.erreurs);
|
||||
response.put("membresImportes", resultat.membresImportes);
|
||||
|
||||
return Response.ok(response).build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'import");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("error", "Erreur lors de l'import: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/export")
|
||||
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
@Operation(summary = "Exporter des membres en Excel, CSV ou PDF")
|
||||
@APIResponse(responseCode = "200", description = "Fichier exporté")
|
||||
public Response exporterMembres(
|
||||
@Parameter(description = "Format d'export") @QueryParam("format") @DefaultValue("EXCEL") String format,
|
||||
@Parameter(description = "ID de l'organisation (optionnel)") @QueryParam("associationId") UUID associationId,
|
||||
@Parameter(description = "Statut des membres") @QueryParam("statut") String statut,
|
||||
@Parameter(description = "Type de membre") @QueryParam("type") String type,
|
||||
@Parameter(description = "Date adhésion début") @QueryParam("dateAdhesionDebut") String dateAdhesionDebut,
|
||||
@Parameter(description = "Date adhésion fin") @QueryParam("dateAdhesionFin") String dateAdhesionFin,
|
||||
@Parameter(description = "Colonnes à exporter") @QueryParam("colonnes") List<String> colonnesExportList,
|
||||
@Parameter(description = "Inclure les en-têtes") @QueryParam("inclureHeaders") @DefaultValue("true") boolean inclureHeaders,
|
||||
@Parameter(description = "Formater les dates") @QueryParam("formaterDates") @DefaultValue("true") boolean formaterDates,
|
||||
@Parameter(description = "Inclure un onglet statistiques (Excel uniquement)") @QueryParam("inclureStatistiques") @DefaultValue("false") boolean inclureStatistiques,
|
||||
@Parameter(description = "Mot de passe pour chiffrer le fichier (optionnel)") @QueryParam("motDePasse") String motDePasse) {
|
||||
|
||||
try {
|
||||
// Récupérer les membres selon les filtres
|
||||
List<MembreDTO> membres = membreService.listerMembresPourExport(
|
||||
associationId, statut, type, dateAdhesionDebut, dateAdhesionFin);
|
||||
|
||||
byte[] exportData;
|
||||
String contentType;
|
||||
String extension;
|
||||
|
||||
List<String> colonnesExport = colonnesExportList != null ? colonnesExportList : new ArrayList<>();
|
||||
|
||||
if ("CSV".equalsIgnoreCase(format)) {
|
||||
exportData = membreService.exporterVersCSV(membres, colonnesExport, inclureHeaders, formaterDates);
|
||||
contentType = "text/csv";
|
||||
extension = "csv";
|
||||
} else {
|
||||
// Pour Excel, inclure les statistiques uniquement si demandé et si format Excel
|
||||
boolean stats = inclureStatistiques && "EXCEL".equalsIgnoreCase(format);
|
||||
exportData = membreService.exporterVersExcel(membres, colonnesExport, inclureHeaders, formaterDates, stats, motDePasse);
|
||||
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
extension = "xlsx";
|
||||
}
|
||||
|
||||
return Response.ok(exportData)
|
||||
.type(contentType)
|
||||
.header("Content-Disposition", "attachment; filename=\"membres_export_" +
|
||||
java.time.LocalDate.now() + "." + extension + "\"")
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'export");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("error", "Erreur lors de l'export: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/import/modele")
|
||||
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
@Operation(summary = "Télécharger le modèle Excel pour l'import")
|
||||
@APIResponse(responseCode = "200", description = "Modèle Excel généré")
|
||||
public Response telechargerModeleImport() {
|
||||
try {
|
||||
byte[] modele = membreService.genererModeleImport();
|
||||
return Response.ok(modele)
|
||||
.header("Content-Disposition", "attachment; filename=\"modele_import_membres.xlsx\"")
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de la génération du modèle");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("error", "Erreur lors de la génération du modèle: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/export/count")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Compter les membres selon les filtres pour l'export")
|
||||
@APIResponse(responseCode = "200", description = "Nombre de membres correspondant aux critères")
|
||||
public Response compterMembresPourExport(
|
||||
@Parameter(description = "ID de l'organisation (optionnel)") @QueryParam("associationId") UUID associationId,
|
||||
@Parameter(description = "Statut des membres") @QueryParam("statut") String statut,
|
||||
@Parameter(description = "Type de membre") @QueryParam("type") String type,
|
||||
@Parameter(description = "Date adhésion début") @QueryParam("dateAdhesionDebut") String dateAdhesionDebut,
|
||||
@Parameter(description = "Date adhésion fin") @QueryParam("dateAdhesionFin") String dateAdhesionFin) {
|
||||
|
||||
try {
|
||||
List<MembreDTO> membres = membreService.listerMembresPourExport(
|
||||
associationId, statut, type, dateAdhesionDebut, dateAdhesionFin);
|
||||
|
||||
return Response.ok(Map.of("count", membres.size())).build();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du comptage des membres");
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(Map.of("error", "Erreur lors du comptage: " + e.getMessage()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user