diff --git a/backend/src/submission/router.py b/backend/src/submission/router.py
index 99a48d6b..683001cb 100644
--- a/backend/src/submission/router.py
+++ b/backend/src/submission/router.py
@@ -2,7 +2,7 @@
from typing import Sequence
from fastapi import APIRouter, Depends, BackgroundTasks
-from fastapi.responses import FileResponse
+from fastapi.responses import FileResponse, StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from src.dependencies import get_async_db
@@ -15,7 +15,7 @@
)
from src.submission.exceptions import FileNotFound
from src.submission.exceptions import FilesNotFound
-from src.submission.utils import upload_files, remove_files
+from src.submission.utils import upload_files, remove_files, zip_stream
from src.user.dependencies import admin_user_validation, get_authenticated_user
from src.user.schemas import User
from . import service
@@ -94,6 +94,12 @@ async def get_file(path: str, submission: Submission = Depends(retrieve_submissi
return FileResponse(path=path)
+@router.get("/{submission_id}/zip", response_class=StreamingResponse)
+async def get_all_files(submission: Submission = Depends(retrieve_submission)):
+ path = submission_path(submission.files_uuid, "")
+ return StreamingResponse(zip_stream(path, submission.group_id), media_type="application/zip")
+
+
@router.get("/{submission_id}/artifacts", response_model=list[File])
async def get_artifacts(submission: Submission = Depends(retrieve_submission)):
if submission.status == Status.InProgress:
diff --git a/backend/src/submission/utils.py b/backend/src/submission/utils.py
index bc741ea6..7e0afe1d 100644
--- a/backend/src/submission/utils.py
+++ b/backend/src/submission/utils.py
@@ -1,6 +1,8 @@
import os
import shutil
import zipfile
+import pathlib
+import io
import fnmatch
from uuid import uuid4
@@ -45,5 +47,16 @@ def upload_files(files: list[UploadFile], project: Project) -> str:
return uuid
+def zip_stream(path, group_id: int):
+ base_path = pathlib.Path(path)
+ data = io.BytesIO()
+ with zipfile.ZipFile(data, mode='w') as z:
+ for f_name in base_path.iterdir():
+ name = f"group_{group_id}/{str(f_name).replace(path, "")}"
+ z.write(f_name, arcname=name)
+ data.seek(0)
+ yield from data
+
+
def remove_files(uuid: str):
shutil.rmtree(submissions_path(uuid))
diff --git a/frontend/src/components/submission/SubmissionCard.vue b/frontend/src/components/submission/SubmissionCard.vue
index 41c4248a..8244dd63 100644
--- a/frontend/src/components/submission/SubmissionCard.vue
+++ b/frontend/src/components/submission/SubmissionCard.vue
@@ -63,6 +63,11 @@
+
+
+ {{ $t("submission.download_all_files") }}
+
+
@@ -91,6 +96,13 @@ const downloadFile = (index: number) => {
const file = files.value![index];
download_file(`/api/submissions/${submission.value!.id}/files/${file.filename}`, file.filename);
};
+
+const downloadAll = () => {
+ download_file(
+ `/api/submissions/${submission.value!.id}/zip`,
+ `submission_group_${submission.value?.group_id}`
+ );
+};