From 042ef2808a688f0109fbcfdfd3b5a1007d5262ab Mon Sep 17 00:00:00 2001
From: Heinz-Ullrich Rings <ullrich.rings@ilr.rwth-aachen.de>
Date: Tue, 22 Oct 2024 15:37:18 +0200
Subject: [PATCH] added to save and load the project list from the backend

---
 UnicadoGUI/Backend/main.py                  | 28 ++++++-
 UnicadoGUI/Backend/requirements.txt         |  3 +-
 UnicadoGUI/Frontend/src/routes/+page.svelte | 45 ++++++++--
 UnicadoGUI/Frontend/src/stores/projects.js  | 93 ++++++++++++++++++---
 4 files changed, 146 insertions(+), 23 deletions(-)

diff --git a/UnicadoGUI/Backend/main.py b/UnicadoGUI/Backend/main.py
index 0cd07cd6..79989766 100644
--- a/UnicadoGUI/Backend/main.py
+++ b/UnicadoGUI/Backend/main.py
@@ -1,11 +1,13 @@
 import configparser
 import json
-from fastapi import FastAPI
+from fastapi import FastAPI, File, UploadFile, HTTPException
 from fastapi.responses import FileResponse
 from fastapi.middleware.cors import CORSMiddleware
 from pydantic import BaseModel
 import xmltodict
 from fastapi.encoders import jsonable_encoder
+import os
+import shutil
 
 #FastAPI Backend for UNICADO Gui
 app = FastAPI()
@@ -110,3 +112,27 @@ async def get_csv(file: str):
 async def get_report(file: str):
     return FileResponse(f"output_files/reportHTML/{file}")
 
+#location for the porject lists
+UPLOAD_DIRECTORY = "./project_lists/"
+
+if not os.path.exists(UPLOAD_DIRECTORY):
+    os.makedirs(UPLOAD_DIRECTORY)
+
+#endpoint to save the project list on the server
+@app.post("/projects/")
+async def upload_project_list(file: UploadFile = File(...)):
+    if not file.filename.endswith(".zip"):
+        raise HTTPException(status_code=400, detail="Only .zip files are allowed")
+    
+    file_path = os.path.join(UPLOAD_DIRECTORY, file.filename)
+
+    with open(file_path, "wb") as buffer:
+        shutil.copyfileobj(file.file, buffer)
+
+    return {"Project list successfully saved"}
+
+#endpoint to get the project list from the server
+@app.get("/projects/")
+async def get_project_list():
+    file_path = UPLOAD_DIRECTORY + "projects.zip"
+    return FileResponse(path=file_path, filename="projects.zip", media_type="application/zip")
\ No newline at end of file
diff --git a/UnicadoGUI/Backend/requirements.txt b/UnicadoGUI/Backend/requirements.txt
index 6fef470e..c884f2f8 100644
--- a/UnicadoGUI/Backend/requirements.txt
+++ b/UnicadoGUI/Backend/requirements.txt
@@ -1,3 +1,4 @@
 xmltodict~=0.13.0
 fastapi~=0.109.2
-pydantic~=1.10.14
\ No newline at end of file
+pydantic~=1.10.14
+python-multipart==0.0.12
\ No newline at end of file
diff --git a/UnicadoGUI/Frontend/src/routes/+page.svelte b/UnicadoGUI/Frontend/src/routes/+page.svelte
index 2fb0897d..2579143a 100644
--- a/UnicadoGUI/Frontend/src/routes/+page.svelte
+++ b/UnicadoGUI/Frontend/src/routes/+page.svelte
@@ -1,6 +1,6 @@
 <script>
     import { Button, Styles, Icon, Modal, ModalHeader, ModalBody, ModalFooter} from "@sveltestrap/sveltestrap";
-    import { addProject, removeProject, saveProjectsAsZip, loadProjectsFromZip } from '../stores/projects';
+    import { addProject, removeProject, saveProjectsAsZip, loadProjectsFromZip, saveProjectsOnServer, loadProjectsFromServer } from '../stores/projects';
     let projectName = '';
     let projectToRemove = '';
     let showModal = false;
@@ -16,7 +16,7 @@
     function deleteProject() {
       if (projectToRemove.trim() !== '') {
         removeProject(projectToRemove);
-        projectToRemove = ''; // Eingabefeld leeren nach dem Hinzufügen
+        projectToRemove = '';
       }
     }
 
@@ -28,13 +28,13 @@
       showModal = false;
     }
     const handleSave = async () => {
-    try {
-      await saveProjectsAsZip(); 
-      console.log("Projects saved successfully");
-    } catch (error) {
-      console.error("Error while trying to save the project list", error);
+        try {
+            await saveProjectsAsZip(); 
+                console.log("Projects saved successfully");
+            } catch (error) {
+                console.error("Error while trying to save the project list", error);
+        }
     }
-  }
 
   function handleFileUpload(/** @type any */event) {
     const selectedFile = event.target.files[0];
@@ -51,6 +51,26 @@
       console.error('file-input not found');
     }
   }
+
+  const triggerFileUpload = async () => {
+        try {
+            await saveProjectsOnServer(); 
+                console.log("Project list saved successfully");
+            } catch (error) {
+                console.error("Error while trying to save the project list", error);
+        }
+    }
+
+
+  const triggerFileDownload = async () => {
+    try {
+            await loadProjectsFromServer(); 
+                console.log("Project list Loaded successfully");
+            } catch (error) {
+                console.error("Error while trying to load the project list", error);
+    }
+  }
+
 </script>
 <h1>Welcome to the UNICADO WebApp</h1>
 
@@ -76,6 +96,15 @@
     Load project Liste von zip-file
 </Button>
 
+<Button on:click={triggerFileUpload}>
+    <Icon name="cloud-upload"/>
+    Save projects list on the server
+</Button>
+
+<Button on:click={triggerFileDownload}>
+    <Icon name="cloud-upload"/>
+    Load project Liste from the server
+</Button>
 {#if showModal}
     <Modal isOpen={showModal} toggle={closeModal}>
         <ModalHeader toggle={closeModal}>Add New Project</ModalHeader>
diff --git a/UnicadoGUI/Frontend/src/stores/projects.js b/UnicadoGUI/Frontend/src/stores/projects.js
index 58a8e136..830e7814 100644
--- a/UnicadoGUI/Frontend/src/stores/projects.js
+++ b/UnicadoGUI/Frontend/src/stores/projects.js
@@ -72,19 +72,8 @@ export const saveProjectsAsZip = async () => {
     projectArray = value;
   })();
 
-  projectArray.forEach((project) => {
-    const folder = zip.folder(project.name);
-
-    if (folder) {
-      const fileContent = JSON.stringify({ id: project.id }, null, 2);
-      folder.file("data.json", fileContent);
-    } else {
-      console.error(`Could not create folder for project: ${project.name}`);
-    }
-  });
-
-  const blob = await zip.generateAsync({ type: "blob" });
-  const url = URL.createObjectURL(blob);
+  const zipBlob = await createZipFile(projectArray);
+  const url = URL.createObjectURL(zipBlob);
   const a = document.createElement('a');
   a.href = url;
   a.download = 'projects.zip';
@@ -92,10 +81,16 @@ export const saveProjectsAsZip = async () => {
   URL.revokeObjectURL(url);
 };
 
+
+
 /**
 * Loads the Project List from a zip file
 */
 export const loadProjectsFromZip = (/** @type {File} */ file) => {
+  loadProjectList(file);
+};
+
+const loadProjectList = async (/** @type {File} */ file) => {
   const zip = new JSZip();
   zip.loadAsync(file).then(async (zipContent) => {
     /** @type {Project[]} */
@@ -126,4 +121,76 @@ export const loadProjectsFromZip = (/** @type {File} */ file) => {
     alert("Error while loading the project list from a file");
     console.error(error);
   });
+}
+
+/**
+ * helper function that parse the project zip file and loads it into the userProject list
+ */
+export const saveProjectsOnServer = async () => {
+  /** @type {Project[]} */
+  let projectArray = [];
+  userProjects.subscribe(value => {
+    projectArray = value;
+  })();
+
+  const zipBlob = await createZipFile(projectArray);
+  const formData = new FormData();
+  formData.append("file", new Blob([zipBlob]), "projects.zip");
+
+  try {
+    const response = await fetch('http://127.0.0.1:8000/projects/', {
+      method: "POST",
+      body: formData,
+    });
+
+    if (!response.ok) {
+      throw new Error("Failed to upload ZIP file");
+    }
+
+    console.log("ZIP file uploaded successfully");
+  } catch (error) {
+    console.error("Error uploading file:", error);
+  }
+}
+
+/**
+ * Function to load the project list from the server
+ */
+export const loadProjectsFromServer = async () => {
+  try {
+    const response = await fetch('http://127.0.0.1:8000/projects/', {
+      method: "GET",
+    });
+    if (!response.ok) {
+      throw new Error("Failed to download the project list");
+    }
+    const blob = await response.blob();
+    const file = new File([blob], "projects.zip", { type: blob.type });
+
+    await loadProjectList(file);
+  } catch (error) {
+    console.error("Error downloading the project list:", error);
+  }
+}
+
+
+/**
+ * helper function:
+ * generates a zip file with all the project files, every project gets its own directory
+ */
+const createZipFile = async (/** @type {Project[]} */ projects) => {
+  const zip = new JSZip();
+
+  projects.forEach((project) => {
+    const folder = zip.folder(project.name);
+
+    if (folder) {
+      const fileContent = JSON.stringify({ id: project.id }, null, 2);
+      folder.file("data.json", fileContent);
+    } else {
+      console.error(`Could not create folder for project: ${project.name}`);
+    }
+  });
+
+  return await zip.generateAsync({ type: "blob" });
 };
\ No newline at end of file
-- 
GitLab