diff --git a/src/main/java/com/olympus/hermione/controllers/FileController.java b/src/main/java/com/olympus/hermione/controllers/FileController.java index 44272b8..d2cd595 100644 --- a/src/main/java/com/olympus/hermione/controllers/FileController.java +++ b/src/main/java/com/olympus/hermione/controllers/FileController.java @@ -7,23 +7,18 @@ import java.util.List; import java.util.Random; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; +import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.netflix.discovery.converters.Auto; -import com.olympus.dto.FileUploadDTO; import com.olympus.hermione.dto.FileDeleteRequest; import com.olympus.hermione.services.FileService; -import com.olympus.model.apollo.KSDocument; -import com.olympus.model.apollo.KSIngestionInfo; @RestController public class FileController { @@ -44,4 +39,12 @@ public class FileController { public ResponseEntity deleteFile(@RequestBody FileDeleteRequest request) { return fileService.deleteFile(request); } + + @GetMapping("/downloadFile") + public ResponseEntity downloadFile( + @RequestParam("filePath") String filePath, + @RequestParam("executionId") String executionId) { + + return fileService.downloadFile(filePath, executionId); + } } diff --git a/src/main/java/com/olympus/hermione/controllers/dashboard/DashboardChatController.java b/src/main/java/com/olympus/hermione/controllers/dashboard/DashboardChatController.java deleted file mode 100644 index 5ba19ae..0000000 --- a/src/main/java/com/olympus/hermione/controllers/dashboard/DashboardChatController.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.olympus.hermione.controllers.dashboard; - -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import com.olympus.hermione.repository.dashboard.DashboardChatModel; -import com.olympus.hermione.repository.dashboard.DashboardScenarioChatRepository; - -@RestController -public class DashboardChatController { - - /*@Autowired - private DashboardScenarioChatRepository scenarioTestChatRepository; - - // Recupera tutti i messaggi - @GetMapping("/chat/all") - public List getAllMessages() { - return scenarioTestChatRepository.findAll(); - } - - // Filtra per userId - @GetMapping("/chat/byUser") - public List getByUserId(@RequestParam String userId) { - return scenarioTestChatRepository.findByUserId(userId); - } - - // Filtra per conversationId - @GetMapping("/chat/byConversation") - public List getByConversationId(@RequestParam String conversationId) { - return scenarioTestChatRepository.findByConversationId(conversationId); - } - - // Filtra per scenarioId - @GetMapping("/chat/byScenario") - public List getByScenarioId(@RequestParam String scenarioId) { - return scenarioTestChatRepository.findByScenarioId(scenarioId); - } - - @PostMapping("/save") - public DashboardChatModel saveMessage(@RequestBody DashboardChatModel message) { //salva i nuovi messaggi - return scenarioTestChatRepository.save(message); - } - */ -} diff --git a/src/main/java/com/olympus/hermione/services/FileService.java b/src/main/java/com/olympus/hermione/services/FileService.java index 411697d..45e8285 100644 --- a/src/main/java/com/olympus/hermione/services/FileService.java +++ b/src/main/java/com/olympus/hermione/services/FileService.java @@ -2,28 +2,24 @@ package com.olympus.hermione.services; import org.springframework.stereotype.Service; import java.io.File; -import java.text.SimpleDateFormat; -import java.util.HashMap; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; -import java.util.Random; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.olympus.dto.FileUploadDTO; import com.olympus.hermione.dto.FileDeleteRequest; -import com.olympus.model.apollo.KSDocument; -import com.olympus.model.apollo.KSIngestionInfo; @Service public class FileService { @@ -147,4 +143,78 @@ public class FileService { return null; } + /** + * Scarica un file dal path specificato + * + * @param filePath Il path relativo del file da scaricare + * @param executionId L'ID dell'esecuzione per il logging + * @return ResponseEntity con il file come Resource + */ + public ResponseEntity downloadFile(String filePath, String executionId) { + try { + logger.info("Downloading file: {} for execution: {}", filePath, executionId); + + // Normalizza il path rimuovendo eventuali separatori doppi o tripli + String normalizedPath = filePath.replaceAll("[\\\\/]+", "/"); + + // Costruisci il path completo del file + Path file = Paths.get(uploadDir, normalizedPath); + + logger.info("Upload directory: {}", uploadDir); + logger.info("Normalized relative path: {}", normalizedPath); + logger.info("Full file path: {}", file.toAbsolutePath()); + + // Verifica che il file esista e sia leggibile + if (!Files.exists(file)) { + logger.error("File not found: {}", file.toAbsolutePath()); + return ResponseEntity.notFound().build(); + } + + if (!Files.isReadable(file)) { + logger.error("File not readable: {}", file.toAbsolutePath()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + // Verifica che il file sia all'interno della directory di upload (security check) + Path uploadPath = Paths.get(uploadDir).toAbsolutePath().normalize(); + Path filePath_abs = file.toAbsolutePath().normalize(); + + if (!filePath_abs.startsWith(uploadPath)) { + logger.error("Security violation: attempting to access file outside upload directory: {}", filePath_abs); + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + // Crea la risorsa file + Resource resource = new FileSystemResource(file); + + // Determina il content type + String contentType = Files.probeContentType(file); + if (contentType == null) { + contentType = "application/octet-stream"; + } + + // Estrai il nome del file + String fileName = file.getFileName().toString(); + + // Costruisci gli header per il download + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\""); + headers.add(HttpHeaders.CONTENT_TYPE, contentType); + headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(resource.contentLength())); + + logger.info("File downloaded successfully: {} (size: {} bytes)", fileName, resource.contentLength()); + + return ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.parseMediaType(contentType)) + .body(resource); + + } catch (IOException e) { + logger.error("Error downloading file: {} - {}", filePath, e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } catch (Exception e) { + logger.error("Unexpected error downloading file: {} - {}", filePath, e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } } diff --git a/src/main/java/com/olympus/hermione/services/ScenarioExecutionService.java b/src/main/java/com/olympus/hermione/services/ScenarioExecutionService.java index 8db4904..7b5d914 100644 --- a/src/main/java/com/olympus/hermione/services/ScenarioExecutionService.java +++ b/src/main/java/com/olympus/hermione/services/ScenarioExecutionService.java @@ -331,16 +331,9 @@ public class ScenarioExecutionService { scenarioExecution.setScenario(scenario); // prendi i file dalla cartella temporanea se รจ presente una chiave con name // "MultiFileUpload" + if (scenarioExecutionInput.getInputs().containsKey("MultiFileUpload")) { folder_name = scenarioExecutionInput.getInputs().get("MultiFileUpload"); - if (folder_name != null && !folder_name.equals("")) { - try { - String base64 = folderToBase64(folder_name); - scenarioExecutionInput.getInputs().put("MultiFileUpload", base64); - } catch (Exception e) { - logger.error("Error while converting folder to base64: " + e.getMessage()); - } - } } if (scenarioExecutionInput.getInputs().containsKey("SingleFileUpload")) { scenarioExecutionInput.getInputs().put("SingleFileUpload",