From cf2eb65bc9cfb6e2029b7b155bc321365b2c7dca Mon Sep 17 00:00:00 2001 From: belthlemar Date: Wed, 18 Sep 2024 16:37:17 +0200 Subject: [PATCH] first draft with little tests --- antarest/core/exceptions.py | 10 +++++++ antarest/study/service.py | 16 +++++++++++ antarest/study/web/raw_studies_blueprint.py | 13 +++++---- tests/integration/test_integration.py | 32 +++++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/antarest/core/exceptions.py b/antarest/core/exceptions.py index dddcda014c..46fd6e38a0 100644 --- a/antarest/core/exceptions.py +++ b/antarest/core/exceptions.py @@ -343,6 +343,16 @@ def __init__(self, is_variant: bool) -> None: super().__init__(HTTPStatus.EXPECTATION_FAILED, "Upgrade not supported for parent of variants") +class FileOrFolderDeletionFailed(HTTPException): + """ + Exception raised when deleting a file or a folder inside the User folder. + """ + + def __init__(self, message: str) -> None: + msg = f"Raw deletion failed because {message}" + super().__init__(HTTPStatus.EXPECTATION_FAILED, msg) + + class ReferencedObjectDeletionNotAllowed(HTTPException): """ Exception raised when a binding constraint is not allowed to be deleted because it references diff --git a/antarest/study/service.py b/antarest/study/service.py index c39576605f..7c6fab7c57 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -34,6 +34,7 @@ BadEditInstructionException, ChildNotFoundError, CommandApplicationError, + FileOrFolderDeletionFailed, IncorrectPathError, NotAManagedStudyException, ReferencedObjectDeletionNotAllowed, @@ -2639,3 +2640,18 @@ def asserts_no_thermal_in_binding_constraints( if ref_bcs: binding_ids = [bc.id for bc in ref_bcs] raise ReferencedObjectDeletionNotAllowed(cluster_id, binding_ids, object_type="Cluster") + + def delete_file_or_folder(self, study_id: str, path: str, current_user: JWTUser) -> None: + study = self.get_study(study_id) + assert_permission(current_user, study, StudyPermissionType.WRITE) + study_tree = self.storage_service.raw_study_service.get_raw(study, True).tree + whole_study_built = study_tree.build() + url = [item for item in path.split("/") if item] + if len(url) == 0: + raise FileOrFolderDeletionFailed(f"the path is invalid: {path}") + try: + whole_study_built["user"].delete(url[1:]) + except ChildNotFoundError as e: + raise FileOrFolderDeletionFailed( + f"the file doesn't exist or you're not inside the 'User' folder: {e.detail}" + ) diff --git a/antarest/study/web/raw_studies_blueprint.py b/antarest/study/web/raw_studies_blueprint.py index 73438f6c3a..41bbc21e27 100644 --- a/antarest/study/web/raw_studies_blueprint.py +++ b/antarest/study/web/raw_studies_blueprint.py @@ -188,14 +188,17 @@ def get_study( @bp.delete( "/studies/{uuid}/raw", tags=[APITag.study_raw_data], - summary="Delete Raw Data from Study: JSON, Text, or File Attachment", + summary="Delete files or folders from Study inside User folder", + response_model=None, ) def delete_file( - uuid: str, - path: str = Param("/", examples=get_path_examples()), # type: ignore - current_user: JWTUser = Depends(auth.get_current_user), + uuid: str, + path: str = Param("/", examples=get_path_examples()), # type: ignore + current_user: JWTUser = Depends(auth.get_current_user), ) -> t.Any: - pass + uuid = sanitize_uuid(uuid) + logger.info(f"Deleting some data for study {uuid}", extra={"user": current_user.id}) + study_service.delete_file_or_folder(uuid, path, current_user) @bp.get( "/studies/{uuid}/areas/aggregate/mc-ind/{output_id}", diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index a136184969..b9cc570030 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -1913,3 +1913,35 @@ def test_links_deletion_with_binding_constraints( # delete the link res = client.delete(f"/v1/studies/{internal_study_id}/links/area_1/area_2") assert res.status_code == 200, res.json() + + +def test_delete_raw(client: TestClient, user_access_token: str, internal_study_id: str) -> None: + client.headers = {"Authorization": f"Bearer {user_access_token}"} + + # ============================= + # SET UP + # ============================= + + # ============================= + # NOMINAL CASES + # ============================= + + # ============================= + # ERRORS + # ============================= + + # try to delete a file which isn't inside the 'User' folder + res = client.delete(f"/v1/studies/{internal_study_id}/raw?path=/input/thermal") + assert res.status_code == 417 + assert res.json()["exception"] == "FileOrFolderDeletionFailed" + assert "the file doesn't exist or you're not inside the 'User' folder" in res.json()["description"] + # With an empty path. + res = client.delete(f"/v1/studies/{internal_study_id}/raw?path=") + assert res.status_code == 417 + assert res.json()["exception"] == "FileOrFolderDeletionFailed" + assert "the path is invalid" in res.json()["description"] + # With a path that doesn't exist + res = client.delete(f"/v1/studies/{internal_study_id}/raw?path=fake_folder/fake_file") + assert res.status_code == 417 + assert res.json()["exception"] == "FileOrFolderDeletionFailed" + assert "the file doesn't exist or you're not inside the 'User' folder" in res.json()["description"]