package com.lions.dev.resource; import com.lions.dev.service.FileService; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; import org.jboss.logging.Logger; import org.jboss.resteasy.reactive.RestForm; import org.jboss.resteasy.reactive.multipart.FileUpload; import jakarta.inject.Inject; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; @Path("/media") public class FileUploadResource { private static final Logger LOG = Logger.getLogger(FileUploadResource.class); @Inject FileService fileService; @Context UriInfo uriInfo; @POST @Path("/upload") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) public Response uploadFile( @RestForm("file") FileUpload file, @RestForm("type") String type, @RestForm("fileName") String fileName, @RestForm("contentType") String contentType, @RestForm("fileSize") String fileSize, @RestForm("userId") String userId) { LOG.info("Début de l'upload de fichier"); LOG.infof("Type: %s, FileName: %s, ContentType: %s, FileSize: %s, UserId: %s", type, fileName, contentType, fileSize, userId); if (file == null || file.uploadedFile() == null) { LOG.error("Aucun fichier fourni dans la requête"); return Response.status(Response.Status.BAD_REQUEST) .entity(createErrorResponse("Aucun fichier fourni")) .build(); } try { // Générer un nom de fichier unique si nécessaire String finalFileName = fileName != null && !fileName.isEmpty() ? fileName : generateUniqueFileName(file.fileName()); // Déterminer le type de média String mediaType = type != null && !type.isEmpty() ? type : determineMediaType(file.fileName()); // Répertoire d'upload String uploadDir = "/tmp/uploads/"; // Sauvegarder le fichier java.nio.file.Path savedFilePath = fileService.saveFile( file.uploadedFile(), uploadDir, finalFileName ); LOG.infof("Fichier sauvegardé avec succès: %s", savedFilePath); // Construire l'URL du fichier // Note: En production, vous devriez utiliser une URL publique (CDN, S3, etc.) String fileUrl = buildFileUrl(finalFileName, uriInfo); String thumbnailUrl = null; // Pour les vidéos, on pourrait générer un thumbnail ici if ("video".equalsIgnoreCase(mediaType)) { // TODO: Générer un thumbnail pour les vidéos thumbnailUrl = fileUrl; // Placeholder } // Construire la réponse JSON Map response = new HashMap<>(); response.put("url", fileUrl); if (thumbnailUrl != null) { response.put("thumbnailUrl", thumbnailUrl); } response.put("type", mediaType); if (fileSize != null && !fileSize.isEmpty()) { try { long size = Long.parseLong(fileSize); // Pour les vidéos, on pourrait calculer la durée ici // response.put("duration", durationInSeconds); } catch (NumberFormatException e) { LOG.warnf("Impossible de parser fileSize: %s", fileSize); } } LOG.infof("Upload réussi, URL: %s", fileUrl); return Response.status(Response.Status.CREATED) .entity(response) .build(); } catch (IOException e) { LOG.errorf(e, "Erreur lors de l'upload du fichier: %s", e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(createErrorResponse("Erreur lors de l'upload du fichier: " + e.getMessage())) .build(); } catch (Exception e) { LOG.errorf(e, "Erreur inattendue lors de l'upload: %s", e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(createErrorResponse("Erreur inattendue.")) .build(); } } /** * Génère un nom de fichier unique. */ private String generateUniqueFileName(String originalFileName) { String extension = ""; int lastDot = originalFileName.lastIndexOf('.'); if (lastDot > 0) { extension = originalFileName.substring(lastDot); } return UUID.randomUUID().toString() + extension; } /** * Détermine le type de média basé sur l'extension du fichier. */ private String determineMediaType(String fileName) { if (fileName == null) { return "image"; } String lowerFileName = fileName.toLowerCase(); if (lowerFileName.endsWith(".mp4") || lowerFileName.endsWith(".mov") || lowerFileName.endsWith(".avi") || lowerFileName.endsWith(".mkv") || lowerFileName.endsWith(".m4v")) { return "video"; } return "image"; } /** * Construit l'URL du fichier. * En production, cela devrait pointer vers un CDN ou un service de stockage. */ private String buildFileUrl(String fileName, UriInfo uriInfo) { // Construire l'URL de base à partir de l'URI de la requête String baseUri = uriInfo.getBaseUri().toString(); // Retirer le slash final s'il existe if (baseUri.endsWith("/")) { baseUri = baseUri.substring(0, baseUri.length() - 1); } // Retourner une URL absolue return baseUri + "/media/files/" + fileName; } @GET @Path("/files/{fileName}") @Produces(MediaType.APPLICATION_OCTET_STREAM) public Response getFile(@PathParam("fileName") String fileName) { try { java.nio.file.Path filePath = java.nio.file.Paths.get("/tmp/uploads/", fileName); if (!java.nio.file.Files.exists(filePath)) { LOG.warnf("Fichier non trouvé: %s", fileName); return Response.status(Response.Status.NOT_FOUND) .entity(createErrorResponse("Fichier non trouvé")) .build(); } // Déterminer le content-type String contentType = determineContentType(fileName); return Response.ok(filePath.toFile()) .type(contentType) .header("Content-Disposition", "inline; filename=\"" + fileName + "\"") .build(); } catch (Exception e) { LOG.errorf(e, "Erreur lors de la récupération du fichier: %s", fileName); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(createErrorResponse("Erreur lors de la récupération du fichier")) .build(); } } /** * Détermine le content-type basé sur l'extension du fichier. */ private String determineContentType(String fileName) { if (fileName == null) { return MediaType.APPLICATION_OCTET_STREAM; } String lowerFileName = fileName.toLowerCase(); if (lowerFileName.endsWith(".jpg") || lowerFileName.endsWith(".jpeg")) { return "image/jpeg"; } else if (lowerFileName.endsWith(".png")) { return "image/png"; } else if (lowerFileName.endsWith(".gif")) { return "image/gif"; } else if (lowerFileName.endsWith(".mp4")) { return "video/mp4"; } else if (lowerFileName.endsWith(".mov")) { return "video/quicktime"; } else if (lowerFileName.endsWith(".avi")) { return "video/x-msvideo"; } return MediaType.APPLICATION_OCTET_STREAM; } /** * Crée une réponse d'erreur JSON. */ private Map createErrorResponse(String message) { Map error = new HashMap<>(); error.put("error", message); return error; } }