Skip to content

Commit 2a69879

Browse files
committed
reduce complexity
1 parent 035ca96 commit 2a69879

File tree

1 file changed

+110
-63
lines changed

1 file changed

+110
-63
lines changed

services/catalog/src/simcore_service_catalog/service/catalog_services.py

Lines changed: 110 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,105 @@ async def check_catalog_service_permissions(
589589
_BatchIdsValidator = create_batch_ids_validator(tuple[ServiceKey, ServiceVersion])
590590

591591

592+
def _evaluate_user_access_rights(
593+
access_rights: list, user_group_ids: set[GroupID]
594+
) -> ServiceGroupAccessRightsV2:
595+
"""Evaluate user's access rights based on their group memberships."""
596+
my_access_rights = ServiceGroupAccessRightsV2(execute=False, write=False)
597+
for ar in access_rights:
598+
if ar.gid in user_group_ids:
599+
my_access_rights.execute |= ar.execute_access
600+
my_access_rights.write |= ar.write_access
601+
return my_access_rights
602+
603+
604+
def _find_service_owner(service_db, access_rights: list) -> GroupID | None:
605+
"""Find service owner from database or access rights."""
606+
owner: GroupID | None = service_db.owner
607+
if not owner:
608+
# NOTE can be more than one. Just get first.
609+
with suppress(StopIteration):
610+
owner = next(
611+
ar.gid for ar in access_rights if ar.write_access and ar.execute_access
612+
)
613+
return owner
614+
615+
616+
async def _get_service_compatibility(
617+
repo: ServicesRepository,
618+
product_name: ProductName,
619+
user_id: UserID,
620+
service_key: ServiceKey,
621+
service_version: ServiceVersion,
622+
my_access_rights: ServiceGroupAccessRightsV2,
623+
) -> Compatibility | None:
624+
"""Get service compatibility if user has access rights."""
625+
if not (my_access_rights.execute or my_access_rights.write):
626+
return None
627+
628+
history = await repo.get_service_history(
629+
product_name=product_name,
630+
user_id=user_id,
631+
key=service_key,
632+
)
633+
compatibility_map = await evaluate_service_compatibility_map(
634+
repo,
635+
product_name=product_name,
636+
user_id=user_id,
637+
service_release_history=history,
638+
)
639+
return compatibility_map.get(service_version)
640+
641+
642+
async def _process_single_service(
643+
repo: ServicesRepository,
644+
product_name: ProductName,
645+
user_id: UserID,
646+
service_key: ServiceKey,
647+
service_version: ServiceVersion,
648+
services_access_rights: dict,
649+
user_group_ids: set[GroupID],
650+
) -> MyServiceGet | None:
651+
"""Process a single service and return MyServiceGet or None if missing."""
652+
# Check access rights
653+
access_rights = services_access_rights.get((service_key, service_version), [])
654+
if not access_rights:
655+
return None
656+
657+
# Evaluate user's access rights
658+
my_access_rights = _evaluate_user_access_rights(access_rights, user_group_ids)
659+
660+
# Get service metadata
661+
service_db = await repo.get_service(
662+
product_name=product_name,
663+
key=service_key,
664+
version=service_version,
665+
)
666+
if not service_db:
667+
return None
668+
669+
# Find service owner
670+
owner = _find_service_owner(service_db, access_rights)
671+
672+
# Evaluate compatibility
673+
compatibility = await _get_service_compatibility(
674+
repo, product_name, user_id, service_key, service_version, my_access_rights
675+
)
676+
677+
return MyServiceGet(
678+
key=service_db.key,
679+
release=ServiceRelease(
680+
version=service_db.version,
681+
version_display=service_db.version_display,
682+
released=service_db.created,
683+
retired=service_db.deprecated,
684+
compatibility=compatibility,
685+
),
686+
owner=owner,
687+
my_access_rights=my_access_rights,
688+
)
689+
690+
592691
async def batch_get_user_services(
593692
repo: ServicesRepository,
594693
groups_repo: GroupsRepository,
@@ -624,72 +723,20 @@ async def batch_get_user_services(
624723
missing = []
625724

626725
for service_key, service_version in unique_service_identifiers:
627-
# Evaluate user's access-rights to this service key:version
628-
access_rights = services_access_rights.get((service_key, service_version), [])
629-
if not access_rights:
630-
missing.append((service_key, service_version))
631-
continue
632-
633-
my_access_rights = ServiceGroupAccessRightsV2(execute=False, write=False)
634-
for ar in access_rights:
635-
if ar.gid in my_group_ids:
636-
my_access_rights.execute |= ar.execute_access
637-
my_access_rights.write |= ar.write_access
638-
639-
# Get service metadata
640-
service_db = await repo.get_service(
641-
product_name=product_name,
642-
key=service_key,
643-
version=service_version,
726+
service_result = await _process_single_service(
727+
repo,
728+
product_name,
729+
user_id,
730+
service_key,
731+
service_version,
732+
services_access_rights,
733+
my_group_ids,
644734
)
645735

646-
if not service_db:
736+
if service_result:
737+
found.append(service_result)
738+
else:
647739
missing.append((service_key, service_version))
648-
continue
649-
650-
# Find service owner (if defined!)
651-
owner: GroupID | None = service_db.owner
652-
if not owner:
653-
# NOTE can be more than one. Just get first.
654-
with suppress(StopIteration):
655-
owner = next(
656-
ar.gid
657-
for ar in access_rights
658-
if ar.write_access and ar.execute_access
659-
)
660-
661-
# Evaluate `compatibility`
662-
compatibility: Compatibility | None = None
663-
if my_access_rights.execute or my_access_rights.write:
664-
history = await repo.get_service_history(
665-
# NOTE: that the service history might be different for each user
666-
# since access rights are defined on a version basis (i.e. one use can have access to v1 but ot to v2)
667-
product_name=product_name,
668-
user_id=user_id,
669-
key=service_key,
670-
)
671-
compatibility_map = await evaluate_service_compatibility_map(
672-
repo,
673-
product_name=product_name,
674-
user_id=user_id,
675-
service_release_history=history,
676-
)
677-
compatibility = compatibility_map.get(service_db.version)
678-
679-
found.append(
680-
MyServiceGet(
681-
key=service_db.key,
682-
release=ServiceRelease(
683-
version=service_db.version,
684-
version_display=service_db.version_display,
685-
released=service_db.created,
686-
retired=service_db.deprecated,
687-
compatibility=compatibility,
688-
),
689-
owner=owner,
690-
my_access_rights=my_access_rights,
691-
)
692-
)
693740

694741
# Check for complete failure scenarios and raise appropriate exceptions
695742
if not found:

0 commit comments

Comments
 (0)