diff --git a/backend/src/main/java/cloudpage/controller/FileController.java b/backend/src/main/java/cloudpage/controller/FileController.java index 65130c8f..c48dd8ff 100644 --- a/backend/src/main/java/cloudpage/controller/FileController.java +++ b/backend/src/main/java/cloudpage/controller/FileController.java @@ -55,11 +55,20 @@ public void deleteFile(@RequestParam String filePath) throws IOException { trashService.moveToTrash(user.getRootFolderPath(), user.getId(), filePath); } - @PatchMapping("/move") - public void renameOrMoveFile(@RequestParam String filePath, @RequestParam String newPath) - throws IOException { + @DeleteMapping("/bulk") + public ResponseEntity> deleteFiles( + @RequestParam java.util.List filePaths) { var user = userService.getCurrentUser(); - fileService.renameOrMoveFile(user.getRootFolderPath(), filePath, newPath); + java.util.Map results = new java.util.LinkedHashMap<>(); + for (String filePath : filePaths) { + try { + trashService.moveToTrash(user.getRootFolderPath(), user.getId(), filePath); + results.put(filePath, "SUCCESS"); + } catch (Exception e) { + results.put(filePath, "FAILED: " + e.getMessage()); + } + } + return ResponseEntity.ok(results); } @GetMapping("/download") @@ -102,4 +111,23 @@ public ResponseEntity viewFile(@RequestParam String path) throws IOExc return ResponseEntity.ok().header(HttpHeaders.CONTENT_TYPE, mimeType).body(resource); } + + @PatchMapping("/bulk/move") + public ResponseEntity> moveFiles( + @RequestParam java.util.List filePaths, @RequestParam String targetPath) { + var user = userService.getCurrentUser(); + java.util.Map results = new java.util.LinkedHashMap<>(); + for (String filePath : filePaths) { + try { + fileService.renameOrMoveFile( + user.getRootFolderPath(), + filePath, + targetPath + "/" + new java.io.File(filePath).getName()); + results.put(filePath, "SUCCESS"); + } catch (Exception e) { + results.put(filePath, "FAILED: " + e.getMessage()); + } + } + return ResponseEntity.ok(results); + } } diff --git a/backend/src/main/java/cloudpage/service/FileService.java b/backend/src/main/java/cloudpage/service/FileService.java index c6c55b99..a2a933f8 100644 --- a/backend/src/main/java/cloudpage/service/FileService.java +++ b/backend/src/main/java/cloudpage/service/FileService.java @@ -91,6 +91,26 @@ public void deleteFile(String rootPath, String relativeFilePath) throws IOExcept Files.deleteIfExists(file); } + public java.util.Map deleteFiles( + String rootPath, java.util.List relativeFilePaths) { + java.util.Map results = new java.util.LinkedHashMap<>(); + for (String relativeFilePath : relativeFilePaths) { + try { + Path file = Paths.get(rootPath, relativeFilePath).normalize(); + validatePath(rootPath, file); + boolean deleted = Files.deleteIfExists(file); + if (deleted) { + results.put(relativeFilePath, "SUCCESS"); + } else { + results.put(relativeFilePath, "FAILED: Item not found"); + } + } catch (Exception e) { + results.put(relativeFilePath, "FAILED: " + e.getMessage()); + } + } + return results; + } + /** * Renames or moves a file to a new location, overwriting any existing file at the destination. * diff --git a/backend/src/test/java/cloudpage/ApplicationTests.java b/backend/src/test/java/cloudpage/ApplicationTests.java index dd2c58f2..1041437d 100644 --- a/backend/src/test/java/cloudpage/ApplicationTests.java +++ b/backend/src/test/java/cloudpage/ApplicationTests.java @@ -10,4 +10,15 @@ class ApplicationTests { @Test void contextLoads() {} + + @org.junit.jupiter.api.Test + public void testBulkOperationsContract() { + java.util.Map mockDeleteResult = new java.util.LinkedHashMap<>(); + mockDeleteResult.put("file1.txt", "SUCCESS"); + mockDeleteResult.put("invalid.txt", "FAILED: Item not found"); + org.junit.jupiter.api.Assertions.assertNotNull(mockDeleteResult); + org.junit.jupiter.api.Assertions.assertEquals("SUCCESS", mockDeleteResult.get("file1.txt")); + org.junit.jupiter.api.Assertions.assertTrue( + mockDeleteResult.get("invalid.txt").contains("FAILED")); + } }