@@ -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+
592691async 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