Skip to content

Commit 96bf18b

Browse files
GitHKAndrei Neagu
andauthored
🎨 replace project_id and node_id with appropriate labels when exporting (#7508)
Co-authored-by: Andrei Neagu <[email protected]>
1 parent 44972f0 commit 96bf18b

File tree

3 files changed

+99
-2
lines changed

3 files changed

+99
-2
lines changed

services/storage/src/simcore_service_storage/simcore_s3_dsm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,7 @@ async def create_s3_export(
13121312

13131313
await create_and_upload_export(
13141314
get_s3_client(self.app),
1315+
ProjectRepository.instance(get_db_engine(self.app)),
13151316
self.simcore_bucket_name,
13161317
source_object_keys=source_object_keys,
13171318
destination_object_keys=destination_object_key,

services/storage/src/simcore_service_storage/utils/simcore_s3_dsm_utils.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from aws_library.s3._constants import STREAM_READER_CHUNK_SIZE
99
from aws_library.s3._models import S3ObjectKey
1010
from models_library.api_schemas_storage.storage_schemas import S3BucketName
11-
from models_library.projects import ProjectID
11+
from models_library.projects import ProjectID, ProjectIDStr
1212
from models_library.projects_nodes_io import (
13+
NodeIDStr,
1314
SimcoreS3DirectoryID,
1415
SimcoreS3FileID,
1516
StorageFileID,
@@ -27,6 +28,7 @@
2728
from ..models import FileMetaData, FileMetaDataAtDB, GenericCursor, PathMetaData
2829
from ..modules.db.access_layer import AccessLayerRepository
2930
from ..modules.db.file_meta_data import FileMetaDataRepository, TotalChildren
31+
from ..modules.db.projects import ProjectRepository
3032
from .utils import convert_db_to_model
3133

3234

@@ -165,17 +167,55 @@ def _base_path_parent(base_path: UserSelectionStr, s3_object: S3ObjectKey) -> st
165167
return f"{result}"
166168

167169

170+
def _get_project_ids(user_selecton: set[UserSelectionStr]) -> list[ProjectID]:
171+
results = []
172+
for selected in user_selecton:
173+
project_id = ProjectID(Path(selected).parts[0])
174+
results.append(project_id)
175+
return results
176+
177+
178+
def _replace_node_id_project_id_in_path(
179+
ids_names_map: dict[ProjectID, dict[ProjectIDStr | NodeIDStr, str]], path: str
180+
) -> str:
181+
path_parts = Path(path).parts
182+
if len(path_parts) == 0:
183+
return path
184+
185+
if len(path_parts) == 1:
186+
return ids_names_map[ProjectID(path)][path].replace("/", "_")
187+
188+
project_id_str = path_parts[0]
189+
project_id = ProjectID(project_id_str)
190+
node_id_str = path_parts[1]
191+
return "/".join(
192+
(
193+
ids_names_map[project_id][project_id_str].replace("/", "_"),
194+
ids_names_map[project_id][node_id_str].replace("/", "_"),
195+
*path_parts[2:],
196+
)
197+
)
198+
199+
168200
async def create_and_upload_export(
169201
s3_client: SimcoreS3API,
202+
project_repository: ProjectRepository,
170203
bucket: S3BucketName,
171204
*,
172205
source_object_keys: set[tuple[UserSelectionStr, StorageFileID]],
173206
destination_object_keys: StorageFileID,
174207
progress_bar: ProgressBarData,
175208
) -> None:
209+
ids_names_map = await project_repository.get_project_id_and_node_id_to_names_map(
210+
project_uuids=_get_project_ids(user_selecton={x[0] for x in source_object_keys})
211+
)
212+
176213
archive_entries: ArchiveEntries = [
177214
(
178-
_base_path_parent(selection, s3_object),
215+
_base_path_parent(
216+
_replace_node_id_project_id_in_path(ids_names_map, selection),
217+
_replace_node_id_project_id_in_path(ids_names_map, s3_object),
218+
),
179219
await s3_client.get_bytes_streamer_from_object(bucket, s3_object),
180220
)
181221
for (selection, s3_object) in source_object_keys

services/storage/tests/unit/test_simcore_s3_dsm_utils.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
from pathlib import Path
2+
from typing import Final
3+
from uuid import UUID
24

35
import pytest
46
from aws_library.s3._models import S3ObjectKey
7+
from models_library.projects import ProjectID, ProjectIDStr
8+
from models_library.projects_nodes_io import NodeIDStr
9+
from simcore_service_storage.models import NodeID
510
from simcore_service_storage.utils.simcore_s3_dsm_utils import (
611
UserSelectionStr,
712
_base_path_parent,
13+
_replace_node_id_project_id_in_path,
814
compute_file_id_prefix,
915
ensure_user_selection_from_same_base_directory,
1016
)
@@ -73,3 +79,53 @@ def test_ensure_user_selection_from_same_base_directory(
7379
ensure_user_selection_from_same_base_directory([f"{x}" for x in user_selection])
7480
== expected
7581
)
82+
83+
84+
_PID1: Final[ProjectID] = UUID(int=1)
85+
_PID2: Final[ProjectID] = UUID(int=2)
86+
_NID1: Final[NodeID] = UUID(int=3)
87+
_NID2: Final[NodeID] = UUID(int=4)
88+
_IDS_NAMES_MAP: Final[dict[ProjectID, dict[ProjectIDStr | NodeIDStr, str]]] = {
89+
_PID1: {
90+
f"{_PID1}": "project one",
91+
f"{_NID1}": "project one -> node one",
92+
f"{_NID2}": "project one -> node two",
93+
},
94+
_PID2: {
95+
f"{_PID2}": "/project/two/",
96+
f"{_NID1}": "/project/two/->/node/one/",
97+
f"{_NID2}": "/project/two/->/node/two/",
98+
},
99+
}
100+
101+
102+
@pytest.mark.parametrize(
103+
"path, expected",
104+
[
105+
("", ""),
106+
(f"{_PID1}", "project one"),
107+
(f"{_PID1}/{_NID1}", "project one/project one -> node one"),
108+
(f"{_PID1}/{_NID1}/something", "project one/project one -> node one/something"),
109+
(f"{_PID1}/{_NID1}/{_NID2}", f"project one/project one -> node one/{_NID2}"),
110+
(
111+
f"{_PID1}/{_NID1}/{_NID2}/something",
112+
f"project one/project one -> node one/{_NID2}/something",
113+
),
114+
(f"{_PID2}", "_project_two_"),
115+
(f"{_PID2}/{_NID1}", "_project_two_/_project_two_->_node_one_"),
116+
(
117+
f"{_PID2}/{_NID1}/something",
118+
"_project_two_/_project_two_->_node_one_/something",
119+
),
120+
(
121+
f"{_PID2}/{_NID1}/{_NID2}",
122+
f"_project_two_/_project_two_->_node_one_/{_NID2}",
123+
),
124+
(
125+
f"{_PID2}/{_NID1}/{_NID2}/something",
126+
f"_project_two_/_project_two_->_node_one_/{_NID2}/something",
127+
),
128+
],
129+
)
130+
def test__replace_node_id_project_id_in_path(path: str, expected: str):
131+
assert _replace_node_id_project_id_in_path(_IDS_NAMES_MAP, path) == expected

0 commit comments

Comments
 (0)