Files
mic-after-work-server-impl-…/src/main/java/com/lions/dev/resource/EstablishmentRatingResource.java
2026-02-05 18:09:30 +00:00

262 lines
12 KiB
Java

package com.lions.dev.resource;
import com.lions.dev.dto.request.establishment.EstablishmentRatingRequestDTO;
import com.lions.dev.dto.response.establishment.EstablishmentRatingResponseDTO;
import com.lions.dev.dto.response.establishment.EstablishmentRatingStatsResponseDTO;
import com.lions.dev.entity.establishment.EstablishmentRating;
import com.lions.dev.security.Permission;
import com.lions.dev.security.RequiresPermission;
import com.lions.dev.service.EstablishmentRatingService;
import com.lions.dev.service.SecurityService;
import com.lions.dev.util.UserRoles;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
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.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import java.util.Map;
import java.util.UUID;
/**
* Ressource REST pour la gestion des notations d'établissements.
*
* SÉCURITÉ : Les lectures sont publiques, les écritures requièrent une authentification.
*
* @since 2.0 - Sécurité JWT + RBAC production-ready
*/
@Path("/establishments/{establishmentId}/ratings")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Establishment Ratings", description = "Opérations liées aux notations des établissements")
public class EstablishmentRatingResource {
@Inject
EstablishmentRatingService ratingService;
@Inject
SecurityService securityService;
private static final Logger LOG = Logger.getLogger(EstablishmentRatingResource.class);
/**
* Soumet une nouvelle note pour un établissement.
* Requiert une authentification JWT.
*/
@POST
@Transactional
@RolesAllowed({UserRoles.USER, UserRoles.OWNER, UserRoles.MANAGER, UserRoles.ADMIN, UserRoles.SUPER_ADMIN})
@RequiresPermission(Permission.REVIEWS_CREATE)
@Operation(summary = "Soumettre une note pour un établissement",
description = "Soumet une nouvelle note (1 à 5 étoiles) pour un établissement. Requiert une authentification JWT.")
@SecurityRequirement(name = "bearerAuth")
@APIResponse(responseCode = "201", description = "Note soumise avec succès")
@APIResponse(responseCode = "401", description = "Non authentifié")
@APIResponse(responseCode = "400", description = "Données invalides")
public Response submitRating(
@PathParam("establishmentId") String establishmentId,
@Valid EstablishmentRatingRequestDTO requestDTO) {
UUID authenticatedUserId = securityService.getCurrentUserId();
LOG.info("Soumission d'une note pour l'établissement " + establishmentId + " par l'utilisateur " + authenticatedUserId);
try {
UUID id = UUID.fromString(establishmentId);
EstablishmentRating rating = ratingService.submitRating(id, authenticatedUserId, requestDTO);
EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating);
return Response.status(Response.Status.CREATED).entity(responseDTO).build();
} catch (IllegalArgumentException e) {
LOG.error("ID invalide : " + e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("ID invalide : " + e.getMessage())
.build();
} catch (RuntimeException e) {
LOG.error("Erreur lors de la soumission de la note : " + e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity(e.getMessage())
.build();
} catch (Exception e) {
LOG.error("Erreur inattendue lors de la soumission de la note", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur lors de la soumission de la note")
.build();
}
}
/**
* Met à jour une note existante.
* Requiert une authentification JWT.
*/
@PUT
@Transactional
@RolesAllowed({UserRoles.USER, UserRoles.OWNER, UserRoles.MANAGER, UserRoles.ADMIN, UserRoles.SUPER_ADMIN})
@RequiresPermission(Permission.REVIEWS_UPDATE_OWN)
@Operation(summary = "Modifier une note existante",
description = "Met à jour une note existante pour un établissement. Requiert une authentification JWT.")
@SecurityRequirement(name = "bearerAuth")
@APIResponse(responseCode = "200", description = "Note mise à jour")
@APIResponse(responseCode = "401", description = "Non authentifié")
@APIResponse(responseCode = "404", description = "Note non trouvée")
public Response updateRating(
@PathParam("establishmentId") String establishmentId,
@Valid EstablishmentRatingRequestDTO requestDTO) {
UUID authenticatedUserId = securityService.getCurrentUserId();
LOG.info("Mise à jour de la note pour l'établissement " + establishmentId + " par l'utilisateur " + authenticatedUserId);
try {
UUID id = UUID.fromString(establishmentId);
EstablishmentRating rating = ratingService.updateRating(id, authenticatedUserId, requestDTO);
EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating);
return Response.ok(responseDTO).build();
} catch (IllegalArgumentException e) {
LOG.error("ID invalide : " + e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("ID invalide : " + e.getMessage())
.build();
} catch (RuntimeException e) {
LOG.error("Erreur lors de la mise à jour de la note : " + e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity(e.getMessage())
.build();
} catch (Exception e) {
LOG.error("Erreur inattendue lors de la mise à jour de la note", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur lors de la mise à jour de la note")
.build();
}
}
/**
* Récupère les statistiques de notation d'un établissement.
* Endpoint public.
*/
@GET
@Path("/stats")
@PermitAll
@Operation(summary = "Récupérer les statistiques de notation",
description = "Récupère les statistiques de notation d'un établissement (moyenne, total, distribution)")
public Response getRatingStats(@PathParam("establishmentId") String establishmentId) {
LOG.info("Récupération des statistiques de notation pour l'établissement " + establishmentId);
try {
UUID id = UUID.fromString(establishmentId);
Map<String, Object> stats = ratingService.getRatingStats(id);
EstablishmentRatingStatsResponseDTO responseDTO = new EstablishmentRatingStatsResponseDTO(
(Double) stats.get("averageRating"),
(Integer) stats.get("totalRatingsCount"),
(Map<Integer, Integer>) stats.get("ratingDistribution")
);
return Response.ok(responseDTO).build();
} catch (IllegalArgumentException e) {
LOG.error("ID invalide : " + e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("ID invalide : " + e.getMessage())
.build();
} catch (Exception e) {
LOG.error("Erreur inattendue lors de la récupération des statistiques", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur lors de la récupération des statistiques")
.build();
}
}
/**
* Récupère la note d'un utilisateur pour un établissement (via path parameter).
* Endpoint public.
*/
@GET
@Path("/users/{userId}")
@PermitAll
@Operation(summary = "Récupérer la note d'un utilisateur (path parameter)",
description = "Récupère la note donnée par un utilisateur spécifique pour un établissement (via path parameter)")
public Response getUserRatingByPath(
@PathParam("establishmentId") String establishmentId,
@PathParam("userId") String userIdStr) {
LOG.info("Récupération de la note de l'utilisateur " + userIdStr + " pour l'établissement " + establishmentId);
try {
UUID id = UUID.fromString(establishmentId);
UUID userId = UUID.fromString(userIdStr);
EstablishmentRating rating = ratingService.getUserRating(id, userId);
if (rating == null) {
return Response.status(Response.Status.NOT_FOUND)
.entity("Note non trouvée")
.build();
}
EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating);
return Response.ok(responseDTO).build();
} catch (IllegalArgumentException e) {
LOG.error("ID invalide : " + e.getMessage(), e);
return Response.status(Response.Status.BAD_REQUEST)
.entity("ID invalide : " + e.getMessage())
.build();
} catch (Exception e) {
LOG.error("Erreur inattendue lors de la récupération de la note", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur lors de la récupération de la note")
.build();
}
}
/**
* Récupère la note d'un utilisateur pour un établissement (via query parameter).
* Endpoint public.
*/
@GET
@PermitAll
@Operation(summary = "Récupérer la note d'un utilisateur",
description = "Récupère la note donnée par un utilisateur spécifique pour un établissement (via query parameter userId)")
public Response getUserRatingByQuery(
@PathParam("establishmentId") String establishmentId,
@QueryParam("userId") String userIdStr) {
LOG.info("Récupération de la note de l'utilisateur " + userIdStr + " pour l'établissement " + establishmentId);
// Si userId n'est pas fourni, retourner une erreur
if (userIdStr == null || userIdStr.isEmpty()) {
LOG.warn("userId manquant dans la requête");
return Response.status(Response.Status.BAD_REQUEST)
.entity("Le paramètre userId est requis")
.build();
}
try {
UUID id = UUID.fromString(establishmentId);
UUID userId = UUID.fromString(userIdStr);
EstablishmentRating rating = ratingService.getUserRating(id, userId);
if (rating == null) {
// Retourner 404 si la note n'existe pas
return Response.status(Response.Status.NOT_FOUND)
.entity("Note non trouvée")
.build();
}
EstablishmentRatingResponseDTO responseDTO = new EstablishmentRatingResponseDTO(rating);
return Response.ok(responseDTO).build();
} catch (IllegalArgumentException e) {
LOG.error("ID invalide : " + e.getMessage(), e);
return Response.status(Response.Status.BAD_REQUEST)
.entity("ID invalide : " + e.getMessage())
.build();
} catch (Exception e) {
LOG.error("Erreur inattendue lors de la récupération de la note", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Erreur lors de la récupération de la note")
.build();
}
}
}