@@ -240,10 +240,42 @@ def get_member_id_from_accessy_id(self, accessy_id: UUID) -> Optional[int]:
240240 def get_all_members (self ) -> list [AccessyMember ]:
241241 """Get a list of all Accessy members in the ORG with GROUPS (lab and special)"""
242242
243- org_member_ids = set (item ["id" ] for item in self ._get_users_org ())
243+ def fill_in_group_affiliation_and_membership_id (members : list [AccessyMember ], group : UUID ) -> None :
244+ group_members = self ._get_users_in_access_group (group )
245+ userId_to_group_member = {m .userId : m for m in group_members }
246+ for member in members :
247+ assert member .user_id is not None
248+ membership = userId_to_group_member .get (member .user_id , None )
249+
250+ if not membership :
251+ continue
252+
253+ member .groups .add (group )
254+ if member .membership_id is None :
255+ member .membership_id = membership .id
256+ elif member .membership_id != membership .id :
257+ raise AccessyError (
258+ f"User { member .name !r} { member .user_id = } has different membership_id for different groups"
259+ f" ({ member .membership_id } != { membership .id } ). This is a bug"
260+ )
261+
262+ def fill_in_membership_id_if_missing (member : AccessyMember ) -> None :
263+ if member .membership_id is None :
264+ member .membership_id = self ._get (
265+ f"/asset/admin/user/{ member .user_id } /organization/{ self .organization_id ()} /membership"
266+ )["id" ]
267+
268+ org_members = [AccessyUser .from_dict (item ) for item in self ._get_users_org ()]
269+ members = [
270+ AccessyMember (user_id = item .id , phone = item .msisdn , name = f"{ item .firstName } { item .lastName } " )
271+ for item in org_members
272+ ]
273+
274+ for group in [ACCESSY_LABACCESS_GROUP , ACCESSY_SPECIAL_LABACCESS_GROUP ]:
275+ fill_in_group_affiliation_and_membership_id (members , group )
244276
245- members = self . _user_ids_to_accessy_members ( org_member_ids )
246- self . _populate_user_groups ( members )
277+ for m in members :
278+ fill_in_membership_id_if_missing ( m )
247279
248280 return members
249281
@@ -510,68 +542,6 @@ def _get_group_description(self, group_id: UUID) -> str:
510542 assert isinstance (name , str )
511543 return name
512544
513- def _user_ids_to_accessy_members (self , user_ids : Iterable [UUID ]) -> list [AccessyMember ]:
514- """Convert a list of User ID:s to AccessyMembers"""
515-
516- APPLICATION_PHONE_NUMBER = object () # Sentinel phone number for applications
517-
518- def fill_user_details (user : AccessyMember ) -> None :
519- assert user .user_id is not None
520- data = self .get_user_details (user .user_id )
521-
522- # API keys do not have phone numbers, set it to sentinel object so we can filter out API keys further down
523- if data .application :
524- user .phone = APPLICATION_PHONE_NUMBER
525- return
526-
527- if data .msisdn is not None :
528- user .phone = data .msisdn
529- else :
530- logger .warning (f"User { user .user_id } does not have a phone number in accessy. { data = } " )
531- user .name = f"{ data .firstName } { data .lastName } "
532-
533- def fill_membership_id (user : AccessyMember ) -> None :
534- data = self ._get (f"/asset/admin/user/{ user .user_id } /organization/{ self .organization_id ()} /membership" )
535- user .membership_id = data ["id" ]
536-
537- exception_during_fetch = None
538- threads = []
539- user_ids = list (user_ids )
540- thread_count = min (4 , len (user_ids ))
541- accessy_members : List [AccessyMember ] = []
542- for i in range (thread_count ):
543- # Chunk the user_ids into equal parts for each thread
544- slice = user_ids [i ::thread_count ]
545- member_slice = [AccessyMember (user_id = uid ) for uid in slice ]
546- accessy_members .extend (member_slice )
547-
548- # Start a thread for each chunk
549- def worker (member_slice : list [AccessyMember ]) -> None :
550- nonlocal exception_during_fetch
551- try :
552- for member in member_slice :
553- fill_user_details (member )
554- fill_membership_id (member )
555- except AccessyError as e :
556- exception_during_fetch = e
557-
558- t = threading .Thread (target = worker , args = (member_slice ,))
559- threads .append (t )
560- t .start ()
561-
562- for t in threads :
563- t .join ()
564-
565- # Filter out API keys
566- accessy_members = [m for m in accessy_members if m .phone is not APPLICATION_PHONE_NUMBER ]
567-
568- if exception_during_fetch :
569- raise RuntimeError (
570- f"One or more threads failed to fetch user details. The last exception as: { exception_during_fetch } "
571- )
572-
573- return accessy_members
574-
575545 def _user_id_to_accessy_member (self , user_id : UUID ) -> AccessyMember | None :
576546 """Convert an Accessy User ID to an AccessyMember object"""
577547
0 commit comments