@@ -78,38 +78,64 @@ def get_user_policy(tokens: dict) -> dict:
7878
7979 The TEAM backend getUserPolicy is async (fires a Lambda and returns immediately
8080 with policy: null). The frontend catches the result via GraphQL subscription.
81- Instead, we compute the policy directly: look up each group's eligibility,
82- resolve OUs to accounts, and build the combined policy.
81+ Instead, we compute the policy directly: list eligibilities once, filter by
82+ the user's identities, resolve OUs to accounts, and build the combined policy.
8383 """
8484 from team_cli .queries import GET_ELIGIBILITY , GET_OU_ACCOUNTS
8585 user = get_user_info (tokens )
86+ identity_ids = _identity_ids (user )
87+
88+ try :
89+ eligibilities = _list_matching_eligibilities (tokens , identity_ids )
90+ except AuthExpiredError :
91+ raise
92+ except APIError :
93+ eligibilities = _get_matching_eligibilities_by_id (tokens , identity_ids , GET_ELIGIBILITY )
94+
95+ eligibility_by_id = {
96+ eligibility .get ("id" ): eligibility
97+ for eligibility in eligibilities
98+ if eligibility and eligibility .get ("id" )
99+ }
100+ ordered_eligibilities = [
101+ eligibility_by_id [identity_id ]
102+ for identity_id in identity_ids
103+ if identity_id in eligibility_by_id
104+ ]
105+
106+ ou_ids = []
107+ seen_ou_ids = set ()
108+ for eligibility in ordered_eligibilities :
109+ for ou in eligibility .get ("ous" ) or []:
110+ ou_id = ou .get ("id" )
111+ if ou_id and ou_id not in seen_ou_ids :
112+ seen_ou_ids .add (ou_id )
113+ ou_ids .append (ou_id )
114+
115+ ou_account_map = {}
116+ if ou_ids :
117+ ou_data = execute (GET_OU_ACCOUNTS , {"ouIds" : ou_ids }, tokens )
118+ for result in (ou_data .get ("getOUAccounts" ) or {}).get ("results" ) or []:
119+ ou_id = result .get ("ouId" )
120+ if ou_id :
121+ ou_account_map [ou_id ] = result .get ("accounts" ) or []
86122
87123 policy_entries = []
88124 max_duration = 0
89125
90- for gid in [user ["user_id" ]] + user ["group_ids" ]:
91- if not gid :
92- continue
93- data = execute (GET_ELIGIBILITY , {"id" : gid }, tokens )
94- elig = data .get ("getEligibility" )
95- if not elig :
96- continue
97-
98- duration = int (elig .get ("duration" ) or 0 )
126+ for eligibility in ordered_eligibilities :
127+ duration = int (eligibility .get ("duration" ) or 0 )
99128 if duration > max_duration :
100129 max_duration = duration
101130
102- accounts = list (elig .get ("accounts" ) or [])
103- ou_ids = [ou ["id" ] for ou in (elig .get ("ous" ) or [])]
104- if ou_ids :
105- ou_data = execute (GET_OU_ACCOUNTS , {"ouIds" : ou_ids }, tokens )
106- for result in (ou_data .get ("getOUAccounts" ) or {}).get ("results" ) or []:
107- accounts .extend (result .get ("accounts" ) or [])
131+ accounts = list (eligibility .get ("accounts" ) or [])
132+ for ou in eligibility .get ("ous" ) or []:
133+ accounts .extend (ou_account_map .get (ou .get ("id" ), []))
108134
109135 policy_entries .append ({
110136 "accounts" : accounts ,
111- "permissions" : elig .get ("permissions" ) or [],
112- "approvalRequired" : elig .get ("approvalRequired" , False ),
137+ "permissions" : eligibility .get ("permissions" ) or [],
138+ "approvalRequired" : eligibility .get ("approvalRequired" , False ),
113139 "duration" : str (max_duration ),
114140 })
115141
@@ -120,6 +146,57 @@ def get_user_policy(tokens: dict) -> dict:
120146 }
121147
122148
149+ def _identity_ids (user : dict ) -> list [str ]:
150+ ids = []
151+ seen = set ()
152+ for identity_id in [user .get ("user_id" )] + list (user .get ("group_ids" ) or []):
153+ if identity_id and identity_id not in seen :
154+ seen .add (identity_id )
155+ ids .append (identity_id )
156+ return ids
157+
158+
159+ def _list_matching_eligibilities (tokens : dict , identity_ids : list [str ]) -> list [dict ]:
160+ from team_cli .queries import LIST_ELIGIBILITIES
161+
162+ identity_id_set = set (identity_ids )
163+ eligibilities = []
164+ next_token = None
165+
166+ while True :
167+ variables = {"limit" : 1000 }
168+ if next_token :
169+ variables ["nextToken" ] = next_token
170+
171+ data = execute (LIST_ELIGIBILITIES , variables , tokens )
172+ result = data .get ("listEligibilities" ) or {}
173+ eligibilities .extend (
174+ eligibility
175+ for eligibility in (result .get ("items" ) or [])
176+ if eligibility and eligibility .get ("id" ) in identity_id_set
177+ )
178+
179+ next_token = result .get ("nextToken" )
180+ if not next_token :
181+ break
182+
183+ return eligibilities
184+
185+
186+ def _get_matching_eligibilities_by_id (
187+ tokens : dict ,
188+ identity_ids : list [str ],
189+ query : str ,
190+ ) -> list [dict ]:
191+ eligibilities = []
192+ for identity_id in identity_ids :
193+ data = execute (query , {"id" : identity_id }, tokens )
194+ eligibility = data .get ("getEligibility" )
195+ if eligibility :
196+ eligibilities .append (eligibility )
197+ return eligibilities
198+
199+
123200def get_requests_by_email (email : str , tokens : dict , status : dict | None = None ) -> list :
124201 """Fetch requests for a given email, with optional status filter. Paginates automatically."""
125202 from team_cli .queries import REQUEST_BY_EMAIL_AND_STATUS
0 commit comments