diff --git a/antarest/study/service.py b/antarest/study/service.py index 7e1198c6b7..71d4bc3881 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -1073,11 +1073,15 @@ def copy_task(notifier: ITaskNotifier) -> TaskResult: return task_or_study_id - def move_study(self, study_id: str, new_folder: str, params: RequestParameters) -> None: + def move_study(self, study_id: str, folder_dest: str, params: RequestParameters) -> None: study = self.get_study(study_id) assert_permission(params.user, study, StudyPermissionType.WRITE) if not is_managed(study): raise NotAManagedStudyException(study_id) + if folder_dest: + new_folder = folder_dest.rstrip("/") + f"/{study.id}" + else: + new_folder = None study.folder = new_folder self.repository.save(study, update_modification_date=False) self.event_bus.push( diff --git a/antarest/study/storage/variantstudy/variant_study_service.py b/antarest/study/storage/variantstudy/variant_study_service.py index a57b7f1b2f..37493be684 100644 --- a/antarest/study/storage/variantstudy/variant_study_service.py +++ b/antarest/study/storage/variantstudy/variant_study_service.py @@ -610,7 +610,7 @@ def create_variant_study(self, uuid: str, name: str, params: RequestParameters) created_at=datetime.utcnow(), updated_at=datetime.utcnow(), version=study.version, - folder=(re.sub(f"/?{study.id}", "", study.folder) if study.folder is not None else None), + folder=(re.sub(study.id, new_id, study.folder) if study.folder is not None else None), groups=study.groups, # Create inherit_group boolean owner_id=params.user.impersonator if params.user else None, snapshot=None, diff --git a/tests/integration/studies_blueprint/test_move.py b/tests/integration/studies_blueprint/test_move.py new file mode 100644 index 0000000000..83defc9aad --- /dev/null +++ b/tests/integration/studies_blueprint/test_move.py @@ -0,0 +1,51 @@ +# Copyright (c) 2024, RTE (https://www.rte-france.com) +# +# See AUTHORS.txt +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 +# +# This file is part of the Antares project. + +from starlette.testclient import TestClient + + +class TestMove: + def test_move_endpoint(self, client: TestClient, internal_study_id: str, user_access_token: str) -> None: + client.headers = {"Authorization": f"Bearer {user_access_token}"} + + res = client.post("/v1/studies?name=study_test") + assert res.status_code == 201 + study_id = res.json() + + # asserts move with a given folder adds the /study_id at the end of the path + res = client.put(f"/v1/studies/{study_id}/move", params={"folder_dest": "folder1"}) + res.raise_for_status() + res = client.get(f"/v1/studies/{study_id}") + assert res.json()["folder"] == f"folder1/{study_id}" + + # asserts move to a folder with //// removes the unwanted `/` + res = client.put(f"/v1/studies/{study_id}/move", params={"folder_dest": "folder2///////"}) + res.raise_for_status() + res = client.get(f"/v1/studies/{study_id}") + assert res.json()["folder"] == f"folder2/{study_id}" + + # asserts the created variant has the same parent folder + res = client.post(f"/v1/studies/{study_id}/variants?name=Variant1") + variant_id = res.json() + res = client.get(f"/v1/studies/{variant_id}") + assert res.json()["folder"] == f"folder2/{variant_id}" + + # asserts move doesn't work on un-managed studies + res = client.put(f"/v1/studies/{internal_study_id}/move", params={"folder_dest": "folder1"}) + assert res.status_code == 422 + assert res.json()["exception"] == "NotAManagedStudyException" + + # asserts users can put back a study at the root folder + res = client.put(f"/v1/studies/{study_id}/move", params={"folder_dest": ""}) + res.raise_for_status() + res = client.get(f"/v1/studies/{study_id}") + assert res.json()["folder"] is None diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 27cb8cf78a..0f691d733f 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -207,7 +207,8 @@ def test_main(client: TestClient, admin_access_token: str) -> None: headers={"Authorization": f'Bearer {george_credentials["access_token"]}'}, ) assert len(res.json()) == 3 - assert filter(lambda s: s["id"] == copied.json(), res.json().values()).__next__()["folder"] == "foo/bar" + moved_study = filter(lambda s: s["id"] == copied.json(), res.json().values()).__next__() + assert moved_study["folder"] == f"foo/bar/{moved_study['id']}" # Study delete client.delete(