Skip to content

Commit 05afcdd

Browse files
committed
draft 3
1 parent 7549430 commit 05afcdd

File tree

3 files changed

+46
-30
lines changed

3 files changed

+46
-30
lines changed

services/catalog/src/simcore_service_catalog/services/compatibility.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,13 @@ async def evaluate_service_compatibility_map(
9696
user_id: UserID,
9797
service_release_history: list[ReleaseDBGet],
9898
) -> dict[ServiceVersion, Compatibility | None]:
99-
released_versions = _convert_to_versions(service_release_history)
100-
result: dict[ServiceVersion, Compatibility | None] = {}
99+
"""
100+
Evaluates the compatibility among a list of service releases for a given product and user.
101101
102+
"""
103+
compatibility_map: dict[ServiceVersion, Compatibility | None] = {}
104+
105+
released_versions = _convert_to_versions(service_release_history)
102106
for release in service_release_history:
103107
compatibility = None
104108
if release.compatibility_policy:
@@ -108,7 +112,7 @@ async def evaluate_service_compatibility_map(
108112
repo=repo,
109113
target_version=release.version,
110114
released_versions=released_versions,
111-
compatibility_policy={**release.compatibility_policy},
115+
compatibility_policy=dict(release.compatibility_policy),
112116
)
113117
elif latest_version := _get_latest_compatible_version(
114118
release.version,
@@ -117,6 +121,6 @@ async def evaluate_service_compatibility_map(
117121
compatibility = Compatibility(
118122
can_update_to=CompatibleService(version=f"{latest_version}")
119123
)
120-
result[release.version] = compatibility
124+
compatibility_map[release.version] = compatibility
121125

122-
return result
126+
return compatibility_map

services/catalog/src/simcore_service_catalog/services/services_api.py

+29-23
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
ServiceGetV2,
66
ServiceUpdateV2,
77
)
8+
from models_library.groups import GroupID
89
from models_library.products import ProductName
910
from models_library.rest_pagination import PageLimitInt
1011
from models_library.services_access import ServiceGroupAccessRightsV2
@@ -363,62 +364,67 @@ async def batch_get_my_services(
363364

364365
my_services = []
365366
for service_key, service_version in ids:
366-
access_rights = services_access_rights.get((service_key, service_version), [])
367-
368-
my_access_rights = {
369-
"execute": False,
370-
"write": False,
371-
}
372367

368+
# Evaluate user's access-rights to this service key:version
369+
access_rights = services_access_rights.get((service_key, service_version), [])
370+
my_access_rights = ServiceGroupAccessRightsV2(execute=False, write=False)
373371
for ar in access_rights:
374372
if ar.gid in my_group_ids:
375-
my_access_rights["execute"] |= ar.execute_access
376-
my_access_rights["write"] |= ar.write_access
373+
my_access_rights.execute |= ar.execute_access
374+
my_access_rights.write |= ar.write_access
377375

376+
# Get service metadata
378377
service_db = await repo.get_service(
379378
product_name=product_name,
380379
key=service_key,
381380
version=service_version,
382381
)
383382
assert service_db # nosec
384383

385-
owner = service_db.owner
384+
# Find service owner
385+
owner: GroupID | None = service_db.owner
386386
if not owner:
387-
# TODO: raise error to indicate that no owner is registered for a given service
387+
# NOTE can be more than one. Just get first.
388388
owner = next(
389389
ar.gid for ar in access_rights if ar.write_access and ar.execute_access
390390
)
391391

392+
# TODO: raise error to indicate that no owner is registered for a given service
392393
assert owner is not None # nosec
393394

394-
compatibility_map = {}
395-
if my_access_rights != {"execute": False, "write": False}:
395+
# Evaluate `compatibility`
396+
compatibility: Compatibility | None = None
397+
if my_access_rights.execute or my_access_rights.write:
398+
# TODO: add cache to this section that evals compatibility_map based on service_key
399+
400+
# NOTE: that the service history might be different for each user
401+
# since access rights are defined on a k:v basis
396402
history = await repo.get_service_history(
397403
product_name=product_name, user_id=user_id, key=service_key
398404
)
399-
if history:
400-
compatibility_map = await evaluate_service_compatibility_map(
401-
repo,
402-
product_name=product_name,
403-
user_id=user_id,
404-
service_release_history=history,
405-
)
405+
assert history # nosec
406+
407+
compatibility_map = await evaluate_service_compatibility_map(
408+
repo,
409+
product_name=product_name,
410+
user_id=user_id,
411+
service_release_history=history,
412+
)
413+
compatibility = compatibility_map.get(service_db.version)
406414

407415
my_services.append(
408416
MyServiceGet(
409417
key=service_db.key,
410-
release=ServiceRelease.model_construct(
418+
release=ServiceRelease(
411419
version=service_db.version,
412420
version_display=service_db.version_display,
413421
released=service_db.created,
414422
retired=service_db.deprecated,
415-
compatibility=compatibility_map.get(service_db.version),
423+
compatibility=compatibility,
416424
),
417425
owner=owner,
418426
my_access_rights=my_access_rights,
419427
)
420428
)
421429

422-
# TODO: else error
423-
424430
return my_services

services/catalog/tests/unit/with_dbs/test_services_services_api.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from models_library.users import UserID
1212
from respx.router import MockRouter
1313
from simcore_service_catalog.api.dependencies.director import get_director_api
14+
from simcore_service_catalog.db.repositories.groups import GroupsRepository
1415
from simcore_service_catalog.db.repositories.services import ServicesRepository
1516
from simcore_service_catalog.services import manifest, services_api
1617
from simcore_service_catalog.services.director import DirectorApi
@@ -29,6 +30,11 @@ def services_repo(sqlalchemy_async_engine: AsyncEngine):
2930
return ServicesRepository(sqlalchemy_async_engine)
3031

3132

33+
@pytest.fixture
34+
def groups_repo(sqlalchemy_async_engine: AsyncEngine):
35+
return GroupsRepository(sqlalchemy_async_engine)
36+
37+
3238
@pytest.fixture
3339
def num_services() -> int:
3440
return 5
@@ -151,8 +157,8 @@ async def test_batch_get_my_services(
151157
mocked_director_service_api: MockRouter,
152158
target_product: ProductName,
153159
services_repo: ServicesRepository,
160+
groups_repo: GroupsRepository,
154161
user_id: UserID,
155-
director_client: DirectorApi,
156162
create_fake_service_data: Callable,
157163
services_db_tables_injector: Callable,
158164
):
@@ -197,7 +203,7 @@ async def test_batch_get_my_services(
197203

198204
my_services = await services_api.batch_get_my_services(
199205
services_repo,
200-
director_client,
206+
groups_repo,
201207
product_name=target_product,
202208
user_id=user_id,
203209
ids=ids,

0 commit comments

Comments
 (0)