From f06bab353985a2f230c1dfdb41bb0abb36aa6bbd Mon Sep 17 00:00:00 2001
From: fabiovandewaeter <vandewaeter.fabio@gmail.com>
Date: Thu, 20 Mar 2025 19:49:07 +0100
Subject: [PATCH] =?UTF-8?q?save=20entrain=20de=20g=C3=A9rer=20upload=20dos?=
 =?UTF-8?q?siers?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                                     |  5 +-
 dossier_serveur_ftp/fichier2                  |  1 +
 .../java/fil/sr2/flopbox/FTPResource.java     | 21 +++++
 src/main/java/fil/sr2/flopbox/FTPService.java | 94 +++++++++++++++++++
 4 files changed, 120 insertions(+), 1 deletion(-)
 create mode 100644 dossier_serveur_ftp/fichier2

diff --git a/README.md b/README.md
index ef4fe88..7b84331 100644
--- a/README.md
+++ b/README.md
@@ -104,12 +104,15 @@ unzip dossier1.zip
 
 - upload fichier :
 ```shell
-curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer valid-token-1" -d '{"alias":"mon-ftp","host":"localhost","port":2121}' http://localhost:8080/ftps
+curl -X PUT -H "Authorization: Bearer valid-token-1" -H "X-FTP-User: user" -H "X-FTP-Pass: password" --upload-file fichier2 http://localhost:8080/ftps/mon-ftp/fichier2
 ```
 
 - upload dossier :
 
 ```shell
+curl -X PUT -H "Authorization: Bearer valid-token-1" -H "X-FTP-User: user" -H "X-FTP-Pass: password" --upload-file dossier2.zip http://localhost:8080/ftps/mon-ftp/dossier2.zip
+
+curl -X POST -H "Authorization: Bearer valid-token-1" -H "X-FTP-User: user" -H "X-FTP-Pass: password" -H "Content-Type: application/octet-stream" --data-binary @dossier2.zip http://localhost:8080/ftps/mon-ftp/upload-dir/
 ```
 
 **Note comprise entre 12 et 13 si—en plus—le proxy FlopBox, permet de télécharger (download) et téléverser (upload) un gros fichier binaire (image, vidéo, etc.):**
diff --git a/dossier_serveur_ftp/fichier2 b/dossier_serveur_ftp/fichier2
new file mode 100644
index 0000000..deae8dc
--- /dev/null
+++ b/dossier_serveur_ftp/fichier2
@@ -0,0 +1 @@
+FICHIER2
diff --git a/src/main/java/fil/sr2/flopbox/FTPResource.java b/src/main/java/fil/sr2/flopbox/FTPResource.java
index 9281a6a..5c48aca 100644
--- a/src/main/java/fil/sr2/flopbox/FTPResource.java
+++ b/src/main/java/fil/sr2/flopbox/FTPResource.java
@@ -162,6 +162,27 @@ public class FTPResource {
         }
     }
 
+    @POST
+    @Path("/{alias}/upload-dir/{path: .*}")
+    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
+    public Response uploadDirectory(
+            @PathParam("alias") String alias,
+            @PathParam("path") String path,
+            @HeaderParam("X-FTP-User") String user,
+            @HeaderParam("X-FTP-Pass") String pass,
+            InputStream zipStream) {
+
+        System.out.println("uploadDirectory()");
+        try {
+            ftpService.uploadDirectoryAsZip(alias, path, user, pass, zipStream);
+            return Response.ok().build();
+        } catch (FTPException e) {
+            return Response.status(e.getStatus()).entity(e.getMessage()).build();
+        } catch (IOException e) {
+            return Response.serverError().entity("Erreur FTP : " + e.getMessage()).build();
+        }
+    }
+
     // POST pour créer une ressource (fichier ou répertoire)
     @POST
     @Path("/{alias}/{path: .+}")
diff --git a/src/main/java/fil/sr2/flopbox/FTPService.java b/src/main/java/fil/sr2/flopbox/FTPService.java
index c380c81..90fe9e0 100644
--- a/src/main/java/fil/sr2/flopbox/FTPService.java
+++ b/src/main/java/fil/sr2/flopbox/FTPService.java
@@ -9,6 +9,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipInputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 
 public class FTPService {
 
@@ -257,4 +261,94 @@ public class FTPService {
             }
         }
     }
+
+    public void uploadDirectoryAsZip(String alias, String targetPath, String user, String pass, InputStream zipStream)
+            throws IOException, FTPException {
+
+        System.out.println("[DEBUG] Début upload ZIP vers: " + targetPath);
+        FTPClient ftp = FTPClientFactory.createClient(alias);
+        try {
+            if (!ftp.login(user, pass)) {
+                throw new FTPException("Authentification FTP échouée", 401);
+            }
+            ftp.enterLocalPassiveMode();
+            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
+
+            try (ZipInputStream zis = new ZipInputStream(zipStream)) {
+                ZipEntry entry;
+                while ((entry = zis.getNextEntry()) != null) {
+                    String entryName = entry.getName();
+                    String fullPath = constructPath(targetPath, entryName);
+                    System.out.println("[DEBUG] Traitement entrée: " + entry.getName()
+                            + " → " + fullPath);
+
+                    if (entry.isDirectory()) {
+                        createDirectories(ftp, fullPath);
+                    } else {
+                        createParentDirectories(ftp, fullPath);
+                        uploadFileEntry(ftp, fullPath, zis);
+                    }
+                    zis.closeEntry();
+                }
+            }
+        } finally {
+            FTPClientFactory.disconnect(ftp);
+        }
+        System.out.println("[DEBUG] Upload ZIP terminé avec succès");
+    }
+
+    private String constructPath(String basePath, String entryPath) {
+        // Ignorer le premier segment du chemin (dossier racine du ZIP)
+        String[] parts = entryPath.split("/");
+        if (parts.length > 1) {
+            String normalizedEntry = String.join("/", Arrays.copyOfRange(parts, 1, parts.length));
+            return basePath.isEmpty() ? normalizedEntry : basePath + "/" + normalizedEntry;
+        }
+        return entryPath; // Cas où l'entrée est déjà à la racine
+    }
+
+    private void createParentDirectories(FTPClient ftp, String filePath) throws IOException {
+        int lastSlash = filePath.lastIndexOf('/');
+        if (lastSlash != -1) {
+            String parentDir = filePath.substring(0, lastSlash);
+            createDirectories(ftp, parentDir);
+        }
+    }
+
+    private void createDirectories(FTPClient ftp, String path) throws IOException {
+        String normalizedPath = path.replaceAll("/+", "/");
+        if (normalizedPath.startsWith("/")) {
+            ftp.changeWorkingDirectory("/");
+        }
+
+        String[] parts = normalizedPath.split("/");
+        StringBuilder currentPath = new StringBuilder();
+
+        for (String part : parts) {
+            if (part.isEmpty())
+                continue;
+
+            currentPath.append(part).append("/");
+
+            if (!ftp.changeWorkingDirectory(currentPath.toString())) {
+                if (!ftp.makeDirectory(currentPath.toString())) {
+                    throw new IOException("Échec création dossier: " + currentPath);
+                }
+                ftp.changeWorkingDirectory(currentPath.toString());
+            }
+        }
+    }
+
+    private void uploadFileEntry(FTPClient ftp, String path, InputStream is)
+            throws IOException, FTPException {
+
+        // Supprimer URLDecoder.decode() !
+        String decodedPath = path;
+
+        try (InputStream bais = is) {
+            if (!ftp.storeFile(decodedPath, bais)) {
+                throw new FTPException("Échec upload: " + decodedPath, 500);
+            }
+        }
+    }
 }
-- 
GitLab