From 2d0574c0250c39adba423e7615a9e2e4e924d2b8 Mon Sep 17 00:00:00 2001 From: Gerwoud Van den Eynden <62761483+Gerwoud@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:16:35 +0100 Subject: [PATCH] Fix for uploading project files (#120) * files are now patchable uncluding the files * fix for uploading a file that is not a zip that it doesn't get saved * unsaved changes * buzoghany requested changes * linter * added rollbacks * extra rollback --- .../endpoints/projects/project_detail.py | 55 +++++++++++++++++-- .../project/endpoints/projects/projects.py | 38 +++++++------ 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/backend/project/endpoints/projects/project_detail.py b/backend/project/endpoints/projects/project_detail.py index c9d9dc03..060587c7 100644 --- a/backend/project/endpoints/projects/project_detail.py +++ b/backend/project/endpoints/projects/project_detail.py @@ -3,20 +3,27 @@ for example /projects/1 if the project id of the corresponding project is 1 """ -from os import getenv +import os +import zipfile from urllib.parse import urljoin from flask import request from flask_restful import Resource +from project.db_in import db + from project.models.project import Project from project.utils.query_agent import query_by_id_from_model, delete_by_id_from_model, \ patch_by_id_from_model from project.utils.authentication import authorize_teacher_or_project_admin, \ authorize_teacher_of_project, authorize_project_visible -API_URL = getenv('API_HOST') +from project.endpoints.projects.endpoint_parser import parse_project_params + +API_URL = os.getenv('API_HOST') RESPONSE_URL = urljoin(API_URL, "projects") +UPLOAD_FOLDER = os.getenv('UPLOAD_URL') + class ProjectDetail(Resource): """ @@ -45,14 +52,54 @@ def patch(self, project_id): Update method for updating a specific project filtered by id of that specific project """ + project_json = parse_project_params() - return patch_by_id_from_model( + output, status_code = patch_by_id_from_model( Project, "project_id", project_id, RESPONSE_URL, - request.json + project_json ) + if status_code != 200: + return output, status_code + + if "assignment_file" in request.files: + file = request.files["assignment_file"] + filename = os.path.basename(file.filename) + project_upload_directory = os.path.join(f"{UPLOAD_FOLDER}", f"{project_id}") + os.makedirs(project_upload_directory, exist_ok=True) + try: + # remove the old file + try: + to_rem_files = os.listdir(project_upload_directory) + for to_rem_file in to_rem_files: + to_rem_file_path = os.path.join(project_upload_directory, to_rem_file) + if os.path.isfile(to_rem_file_path): + os.remove(to_rem_file_path) + except FileNotFoundError: + db.session.rollback() + return ({ + "message": "Something went wrong deleting the old project files", + "url": f"{API_URL}/projects/{project_id}" + }) + + # removed all files now upload the new files + file.save(os.path.join(project_upload_directory, filename)) + zip_location = os.path.join(project_upload_directory, filename) + with zipfile.ZipFile(zip_location) as upload_zip: + upload_zip.extractall(project_upload_directory) + project_json["assignment_file"] = filename + except zipfile.BadZipfile: + db.session.rollback() + return ({ + "message": + "Please provide a valid .zip file for updating the instructions", + "url": f"{API_URL}/projects/{project_id}" + }, + 400) + + return output, status_code @authorize_teacher_of_project def delete(self, project_id): diff --git a/backend/project/endpoints/projects/projects.py b/backend/project/endpoints/projects/projects.py index ccbdca70..b0afa4f8 100644 --- a/backend/project/endpoints/projects/projects.py +++ b/backend/project/endpoints/projects/projects.py @@ -9,6 +9,8 @@ from flask import request, jsonify from flask_restful import Resource +from project.db_in import db + from project.models.project import Project from project.utils.query_agent import query_selected_from_model, create_model_instance from project.utils.authentication import authorize_teacher @@ -18,6 +20,7 @@ API_URL = os.getenv('API_HOST') UPLOAD_FOLDER = os.getenv('UPLOAD_URL') + class ProjectsEndpoint(Resource): """ Class for projects endpoints @@ -47,10 +50,12 @@ def post(self, teacher_id=None): using flask_restfull parse lib """ - file = request.files["assignment_file"] project_json = parse_project_params() - filename = os.path.basename(file.filename) - project_json["assignment_file"] = filename + filename = None + if "assignment_file" in request.files: + file = request.files["assignment_file"] + filename = os.path.basename(file.filename) + project_json["assignment_file"] = filename # save the file that is given with the request try: @@ -73,20 +78,21 @@ def post(self, teacher_id=None): return new_project, status_code project_upload_directory = os.path.join(f"{UPLOAD_FOLDER}", f"{new_project.project_id}") - os.makedirs(project_upload_directory, exist_ok=True) - - file.save(os.path.join(project_upload_directory, filename)) - try: - with zipfile.ZipFile(os.path.join(project_upload_directory, filename)) as upload_zip: - upload_zip.extractall(project_upload_directory) - except zipfile.BadZipfile: - return ({ - "message": "Please provide a .zip file for uploading the instructions", - "url": f"{API_URL}/projects" - }, - 400) - + if filename is not None: + try: + file.save(os.path.join(project_upload_directory, filename)) + zip_location = os.path.join(project_upload_directory, filename) + with zipfile.ZipFile(zip_location) as upload_zip: + upload_zip.extractall(project_upload_directory) + except zipfile.BadZipfile: + os.remove(os.path.join(project_upload_directory, filename)) + db.session.rollback() + return ({ + "message": "Please provide a .zip file for uploading the instructions", + "url": f"{API_URL}/projects" + }, + 400) return { "message": "Project created succesfully", "data": new_project,