ipulse-shared-core-ftredge 19.0.1__py3-none-any.whl → 22.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ipulse-shared-core-ftredge might be problematic. Click here for more details.
- ipulse_shared_core_ftredge/cache/shared_cache.py +1 -2
- ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +4 -4
- ipulse_shared_core_ftredge/exceptions/base_exceptions.py +23 -0
- ipulse_shared_core_ftredge/models/__init__.py +3 -7
- ipulse_shared_core_ftredge/models/base_data_model.py +17 -19
- ipulse_shared_core_ftredge/models/catalog/__init__.py +10 -0
- ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +273 -0
- ipulse_shared_core_ftredge/models/catalog/usertype.py +170 -0
- ipulse_shared_core_ftredge/models/user/__init__.py +5 -0
- ipulse_shared_core_ftredge/models/user/user_permissions.py +66 -0
- ipulse_shared_core_ftredge/models/{subscription.py → user/user_subscription.py} +66 -20
- ipulse_shared_core_ftredge/models/{user_auth.py → user/userauth.py} +19 -10
- ipulse_shared_core_ftredge/models/{user_profile.py → user/userprofile.py} +53 -21
- ipulse_shared_core_ftredge/models/user/userstatus.py +430 -0
- ipulse_shared_core_ftredge/monitoring/__init__.py +2 -2
- ipulse_shared_core_ftredge/monitoring/tracemon.py +320 -0
- ipulse_shared_core_ftredge/services/__init__.py +11 -13
- ipulse_shared_core_ftredge/services/base/__init__.py +3 -1
- ipulse_shared_core_ftredge/services/base/base_firestore_service.py +73 -14
- ipulse_shared_core_ftredge/services/{cache_aware_firestore_service.py → base/cache_aware_firestore_service.py} +46 -32
- ipulse_shared_core_ftredge/services/catalog/__init__.py +14 -0
- ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +273 -0
- ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +307 -0
- ipulse_shared_core_ftredge/services/charging_processors.py +25 -25
- ipulse_shared_core_ftredge/services/user/__init__.py +5 -25
- ipulse_shared_core_ftredge/services/user/firebase_auth_admin_helpers.py +160 -0
- ipulse_shared_core_ftredge/services/user/user_core_service.py +423 -515
- ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +726 -0
- ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +392 -0
- ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +484 -0
- ipulse_shared_core_ftredge/services/user/userauth_operations.py +928 -0
- ipulse_shared_core_ftredge/services/user/userprofile_operations.py +166 -0
- ipulse_shared_core_ftredge/services/user/userstatus_operations.py +212 -0
- ipulse_shared_core_ftredge/services/{charging_service.py → user_charging_service.py} +9 -9
- {ipulse_shared_core_ftredge-19.0.1.dist-info → ipulse_shared_core_ftredge-22.1.1.dist-info}/METADATA +3 -4
- ipulse_shared_core_ftredge-22.1.1.dist-info/RECORD +51 -0
- ipulse_shared_core_ftredge/models/user_status.py +0 -495
- ipulse_shared_core_ftredge/monitoring/microservmon.py +0 -483
- ipulse_shared_core_ftredge/services/user/iam_management_operations.py +0 -326
- ipulse_shared_core_ftredge/services/user/subscription_management_operations.py +0 -384
- ipulse_shared_core_ftredge/services/user/user_account_operations.py +0 -479
- ipulse_shared_core_ftredge/services/user/user_auth_operations.py +0 -305
- ipulse_shared_core_ftredge/services/user/user_holistic_operations.py +0 -436
- ipulse_shared_core_ftredge-19.0.1.dist-info/RECORD +0 -41
- {ipulse_shared_core_ftredge-19.0.1.dist-info → ipulse_shared_core_ftredge-22.1.1.dist-info}/WHEEL +0 -0
- {ipulse_shared_core_ftredge-19.0.1.dist-info → ipulse_shared_core_ftredge-22.1.1.dist-info}/licenses/LICENCE +0 -0
- {ipulse_shared_core_ftredge-19.0.1.dist-info → ipulse_shared_core_ftredge-22.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Useriam Management Operations - Handle user permissions and access rights
|
|
3
|
+
"""
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Dict, Optional, List
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from ipulse_shared_base_ftredge.enums.enums_iam import IAMUnit
|
|
8
|
+
from ...models import UserPermission
|
|
9
|
+
from .userstatus_operations import UserstatusOperations
|
|
10
|
+
from ...exceptions import IAMPermissionError, UserStatusError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class UserpermissionsOperations:
|
|
14
|
+
"""
|
|
15
|
+
Handles IAM permissions and access rights management
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
userstatus_ops: UserstatusOperations,
|
|
21
|
+
logger: Optional[logging.Logger] = None
|
|
22
|
+
):
|
|
23
|
+
self.userstatus_ops = userstatus_ops
|
|
24
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# IAM Permission Operations
|
|
27
|
+
|
|
28
|
+
async def add_permission_to_user(
|
|
29
|
+
self,
|
|
30
|
+
user_uid: str,
|
|
31
|
+
permission: UserPermission,
|
|
32
|
+
updater_uid: Optional[str] = None
|
|
33
|
+
) -> bool:
|
|
34
|
+
"""
|
|
35
|
+
Adds a permission to a user using a UserPermission object.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
user_uid: The user ID to add permission to
|
|
39
|
+
permission: UserPermission object containing all permission details
|
|
40
|
+
updater_uid: The ID of the user performing the update
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
True if permission was added successfully
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
UserStatusError: If user status not found
|
|
47
|
+
IAMPermissionError: If permission addition fails
|
|
48
|
+
"""
|
|
49
|
+
self.logger.info(f"Adding {permission.iam_unit_type.value} permission for user {user_uid}: "
|
|
50
|
+
f"domain='{permission.domain}', name='{permission.permission_ref}'")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
userstatus = await self.userstatus_ops.get_userstatus(user_uid)
|
|
54
|
+
if not userstatus:
|
|
55
|
+
raise UserStatusError(f"UserStatus not found for user_uid {user_uid}")
|
|
56
|
+
|
|
57
|
+
# Use the model's method to add the permission directly
|
|
58
|
+
userstatus.add_permission(permission)
|
|
59
|
+
|
|
60
|
+
# Update the user status with the modified model
|
|
61
|
+
await self.userstatus_ops.update_userstatus(
|
|
62
|
+
user_uid=user_uid,
|
|
63
|
+
status_data=userstatus.model_dump(exclude_none=True),
|
|
64
|
+
updater_uid=updater_uid or "system"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self.logger.info(f"Successfully added permission for user {user_uid}")
|
|
68
|
+
return True
|
|
69
|
+
|
|
70
|
+
except UserStatusError as e:
|
|
71
|
+
self.logger.error("UserStatusError in add_permission_to_user: %s", e, exc_info=True)
|
|
72
|
+
raise
|
|
73
|
+
except Exception as e:
|
|
74
|
+
self.logger.error("Failed to add permission for user %s: %s", user_uid, e, exc_info=True)
|
|
75
|
+
raise IAMPermissionError(
|
|
76
|
+
detail=f"Failed to add permission: {str(e)}",
|
|
77
|
+
user_uid=user_uid,
|
|
78
|
+
operation="add_permission_to_user",
|
|
79
|
+
original_error=e
|
|
80
|
+
) from e
|
|
81
|
+
|
|
82
|
+
async def remove_permission_from_user(
|
|
83
|
+
self,
|
|
84
|
+
user_uid: str,
|
|
85
|
+
domain: Optional[str] = None,
|
|
86
|
+
permission_type: Optional[IAMUnit] = None,
|
|
87
|
+
permission_name: Optional[str] = None,
|
|
88
|
+
source: Optional[str] = None,
|
|
89
|
+
updater_uid: Optional[str] = None
|
|
90
|
+
) -> bool:
|
|
91
|
+
"""
|
|
92
|
+
Removes permissions from a user based on flexible filter criteria.
|
|
93
|
+
At least one filter criteria must be provided.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
user_uid: The user ID to remove permission from
|
|
97
|
+
domain: Optional domain filter (e.g., 'papp')
|
|
98
|
+
permission_type: Optional IAM assignment type filter (GROUP, ROLE, etc.)
|
|
99
|
+
permission_name: Optional permission name filter
|
|
100
|
+
source: Optional source filter
|
|
101
|
+
updater_uid: The ID of the user performing the update
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if permission(s) were removed successfully
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
UserStatusError: If user status not found
|
|
108
|
+
IAMPermissionError: If permission removal fails
|
|
109
|
+
ValueError: If no filter criteria are provided
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
# Remove specific permission
|
|
113
|
+
await remove_permission_from_user(uid, domain="papp", permission_type=IAMUnit.ROLE, permission_name="analyst")
|
|
114
|
+
|
|
115
|
+
# Remove all permissions from a domain
|
|
116
|
+
await remove_permission_from_user(uid, domain="papp")
|
|
117
|
+
|
|
118
|
+
# Remove all permissions of a specific type
|
|
119
|
+
await remove_permission_from_user(uid, permission_type=IAMUnit.ROLE)
|
|
120
|
+
|
|
121
|
+
# Remove all permissions from a source
|
|
122
|
+
await remove_permission_from_user(uid, source="subscription_123")
|
|
123
|
+
"""
|
|
124
|
+
if not any([domain, permission_type, permission_name, source]):
|
|
125
|
+
raise ValueError("At least one filter criteria must be provided")
|
|
126
|
+
|
|
127
|
+
# Build description for logging
|
|
128
|
+
filters = []
|
|
129
|
+
if domain: filters.append(f"domain='{domain}'")
|
|
130
|
+
if permission_type: filters.append(f"type='{permission_type.value}'")
|
|
131
|
+
if permission_name: filters.append(f"name='{permission_name}'")
|
|
132
|
+
if source: filters.append(f"source='{source}'")
|
|
133
|
+
|
|
134
|
+
filter_desc = ", ".join(filters)
|
|
135
|
+
self.logger.info(f"Removing permissions for user {user_uid} with filters: {filter_desc}")
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
userstatus = await self.userstatus_ops.get_userstatus(user_uid)
|
|
139
|
+
if not userstatus:
|
|
140
|
+
raise UserStatusError(f"UserStatus not found for user_uid {user_uid}")
|
|
141
|
+
|
|
142
|
+
# Use the model's method to remove the permission assignment
|
|
143
|
+
removed_count = userstatus.remove_permission(
|
|
144
|
+
domain=domain,
|
|
145
|
+
iam_unit_type=permission_type,
|
|
146
|
+
permission_ref=permission_name,
|
|
147
|
+
source=source
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if removed_count > 0:
|
|
151
|
+
# Update using the full model to maintain consistency
|
|
152
|
+
await self.userstatus_ops.update_userstatus(
|
|
153
|
+
user_uid=user_uid,
|
|
154
|
+
status_data=userstatus.model_dump(exclude_none=True),
|
|
155
|
+
updater_uid=updater_uid or "system"
|
|
156
|
+
)
|
|
157
|
+
self.logger.info(f"Successfully removed {removed_count} permission(s) for user {user_uid}")
|
|
158
|
+
return True
|
|
159
|
+
else:
|
|
160
|
+
self.logger.warning("No matching permissions found for user %s with filters: %s", user_uid, filter_desc)
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
except ValueError as e:
|
|
164
|
+
self.logger.error("Invalid parameters in remove_permission_from_user: %s", e)
|
|
165
|
+
raise IAMPermissionError(
|
|
166
|
+
detail=f"Invalid parameters: {str(e)}",
|
|
167
|
+
user_uid=user_uid,
|
|
168
|
+
operation="remove_permission_from_user",
|
|
169
|
+
original_error=e
|
|
170
|
+
) from e
|
|
171
|
+
except UserStatusError as e:
|
|
172
|
+
self.logger.error("UserStatusError in remove_permission_from_user: %s", e, exc_info=True)
|
|
173
|
+
raise
|
|
174
|
+
except Exception as e:
|
|
175
|
+
self.logger.error("Failed to remove permission for user %s: %s", user_uid, e, exc_info=True)
|
|
176
|
+
raise IAMPermissionError(
|
|
177
|
+
detail=f"Failed to remove permission: {str(e)}",
|
|
178
|
+
user_uid=user_uid,
|
|
179
|
+
operation="remove_permission_from_user",
|
|
180
|
+
original_error=e
|
|
181
|
+
) from e
|
|
182
|
+
|
|
183
|
+
async def cleanup_expired_permissions_of_user(
|
|
184
|
+
self,
|
|
185
|
+
user_uid: str,
|
|
186
|
+
iam_unit_type: Optional[IAMUnit] = None,
|
|
187
|
+
updater_uid: Optional[str] = None
|
|
188
|
+
) -> int:
|
|
189
|
+
"""
|
|
190
|
+
Clean up expired permissions for a user.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
user_uid: The user identifier
|
|
194
|
+
iam_unit_type: Optional filter for specific permission type
|
|
195
|
+
updater_uid: The ID of the user performing the cleanup
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
Number of permissions removed
|
|
199
|
+
"""
|
|
200
|
+
self.logger.info(f"Cleaning up expired permissions for user {user_uid}")
|
|
201
|
+
try:
|
|
202
|
+
userstatus = await self.userstatus_ops.get_userstatus(user_uid)
|
|
203
|
+
if not userstatus:
|
|
204
|
+
raise UserStatusError(f"UserStatus not found for user_uid {user_uid}")
|
|
205
|
+
|
|
206
|
+
removed_count = userstatus.cleanup_expired_permissions(iam_unit_type=iam_unit_type)
|
|
207
|
+
|
|
208
|
+
if removed_count > 0:
|
|
209
|
+
await self.userstatus_ops.update_userstatus(
|
|
210
|
+
user_uid=user_uid,
|
|
211
|
+
status_data=userstatus.model_dump(),
|
|
212
|
+
updater_uid=updater_uid or "system_cleanup_expired_permissions"
|
|
213
|
+
)
|
|
214
|
+
self.logger.info(f"Removed {removed_count} expired permissions for user {user_uid}")
|
|
215
|
+
|
|
216
|
+
return removed_count
|
|
217
|
+
|
|
218
|
+
except UserStatusError as e:
|
|
219
|
+
self.logger.error("UserStatusError in cleanup_expired_permissions_of_user: %s", e, exc_info=True)
|
|
220
|
+
raise
|
|
221
|
+
except Exception as e:
|
|
222
|
+
self.logger.error("Failed to cleanup expired permissions for user %s: %s", user_uid, e, exc_info=True)
|
|
223
|
+
raise IAMPermissionError(
|
|
224
|
+
detail=f"Failed to cleanup expired permissions: {str(e)}",
|
|
225
|
+
user_uid=user_uid,
|
|
226
|
+
operation="cleanup_expired_permissions",
|
|
227
|
+
original_error=e
|
|
228
|
+
) from e
|
|
229
|
+
|
|
230
|
+
async def remove_all_permissions_from_user(
|
|
231
|
+
self,
|
|
232
|
+
user_uid: str,
|
|
233
|
+
source: Optional[str] = None,
|
|
234
|
+
updater_uid: Optional[str] = None
|
|
235
|
+
) -> int:
|
|
236
|
+
"""
|
|
237
|
+
Remove all permissions from a user, optionally filtered by source.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
user_uid: The user identifier
|
|
241
|
+
source: Optional source filter (if None, removes all permissions)
|
|
242
|
+
updater_uid: The ID of the user performing the update
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Number of permissions removed
|
|
246
|
+
"""
|
|
247
|
+
self.logger.info(f"Removing all permissions from user {user_uid}" +
|
|
248
|
+
(f" with source {source}" if source else ""))
|
|
249
|
+
try:
|
|
250
|
+
userstatus = await self.userstatus_ops.get_userstatus(user_uid)
|
|
251
|
+
if not userstatus:
|
|
252
|
+
raise UserStatusError(f"UserStatus not found for user_uid {user_uid}")
|
|
253
|
+
|
|
254
|
+
removed_count = userstatus.remove_all_permissions(source=source)
|
|
255
|
+
|
|
256
|
+
if removed_count > 0:
|
|
257
|
+
await self.userstatus_ops.update_userstatus(
|
|
258
|
+
user_uid=user_uid,
|
|
259
|
+
status_data=userstatus.model_dump(),
|
|
260
|
+
updater_uid=updater_uid or "system_remove_all_permissions"
|
|
261
|
+
)
|
|
262
|
+
self.logger.info(f"Removed {removed_count} permissions from user {user_uid}")
|
|
263
|
+
|
|
264
|
+
return removed_count
|
|
265
|
+
|
|
266
|
+
except UserStatusError as e:
|
|
267
|
+
self.logger.error("UserStatusError in remove_all_permissions_from_user: %s", e, exc_info=True)
|
|
268
|
+
raise
|
|
269
|
+
except Exception as e:
|
|
270
|
+
self.logger.error("Failed to remove all permissions from user %s: %s", user_uid, e, exc_info=True)
|
|
271
|
+
raise IAMPermissionError(
|
|
272
|
+
detail=f"Failed to remove all permissions: {str(e)}",
|
|
273
|
+
user_uid=user_uid,
|
|
274
|
+
operation="remove_all_permissions",
|
|
275
|
+
original_error=e
|
|
276
|
+
) from e
|
|
277
|
+
|
|
278
|
+
async def get_permissions_of_user(
|
|
279
|
+
self,
|
|
280
|
+
user_uid: str,
|
|
281
|
+
valid_post_expir_date: Optional[datetime] = None,
|
|
282
|
+
domain: Optional[str] = None,
|
|
283
|
+
iam_unit_type: Optional[IAMUnit] = None,
|
|
284
|
+
source: Optional[str] = None
|
|
285
|
+
) -> List[UserPermission]:
|
|
286
|
+
"""
|
|
287
|
+
Retrieves IAM permissions for a user with flexible filtering options.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
user_uid: The user identifier
|
|
291
|
+
valid_post_expir_date: If provided, only return permissions valid after this date
|
|
292
|
+
domain: Optional domain filter
|
|
293
|
+
iam_unit_type: Optional IAM unit type filter
|
|
294
|
+
source: Optional source filter
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
List of matching UserPermission objects
|
|
298
|
+
"""
|
|
299
|
+
self.logger.info(f"Getting permissions for user {user_uid} with filters")
|
|
300
|
+
try:
|
|
301
|
+
userstatus = await self.userstatus_ops.get_userstatus(user_uid)
|
|
302
|
+
if not userstatus:
|
|
303
|
+
raise UserStatusError(f"UserStatus not found for user_uid {user_uid}")
|
|
304
|
+
|
|
305
|
+
permissions = userstatus.iam_permissions
|
|
306
|
+
|
|
307
|
+
# Apply filters
|
|
308
|
+
if valid_post_expir_date:
|
|
309
|
+
permissions = [
|
|
310
|
+
perm for perm in permissions
|
|
311
|
+
if perm.expires_at is None or perm.expires_at > valid_post_expir_date
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
if domain:
|
|
315
|
+
permissions = [perm for perm in permissions if perm.domain == domain]
|
|
316
|
+
|
|
317
|
+
if iam_unit_type:
|
|
318
|
+
permissions = [perm for perm in permissions if perm.iam_unit_type == iam_unit_type]
|
|
319
|
+
|
|
320
|
+
if source:
|
|
321
|
+
permissions = [perm for perm in permissions if perm.source == source]
|
|
322
|
+
|
|
323
|
+
return permissions
|
|
324
|
+
|
|
325
|
+
except UserStatusError as e:
|
|
326
|
+
self.logger.error("UserStatusError in get_permissions_of_user: %s", e, exc_info=True)
|
|
327
|
+
raise
|
|
328
|
+
except Exception as e:
|
|
329
|
+
self.logger.error("Failed to get permissions for user %s: %s", user_uid, e, exc_info=True)
|
|
330
|
+
raise IAMPermissionError(
|
|
331
|
+
detail=f"Failed to get permissions: {str(e)}",
|
|
332
|
+
user_uid=user_uid,
|
|
333
|
+
operation="get_user_permissions",
|
|
334
|
+
original_error=e
|
|
335
|
+
) from e
|
|
336
|
+
|
|
337
|
+
async def get_bulk_users_with_permission(
|
|
338
|
+
self,
|
|
339
|
+
domain: str,
|
|
340
|
+
iam_unit_type: IAMUnit,
|
|
341
|
+
permission_ref: str,
|
|
342
|
+
limit: int = 100,
|
|
343
|
+
valid_only: bool = True
|
|
344
|
+
) -> List[str]:
|
|
345
|
+
"""
|
|
346
|
+
Get a list of user UIDs who have a specific permission.
|
|
347
|
+
|
|
348
|
+
Note: This is a basic implementation that queries the database.
|
|
349
|
+
For production use with large datasets, consider implementing
|
|
350
|
+
database-level queries for better performance.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
domain: The domain for the permission
|
|
354
|
+
iam_unit_type: Type of IAM assignment
|
|
355
|
+
permission_ref: The permission identifier
|
|
356
|
+
limit: Maximum number of users to return (default: 100)
|
|
357
|
+
valid_only: If True, only return users with valid (non-expired) permissions
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
List of user UIDs
|
|
361
|
+
"""
|
|
362
|
+
self.logger.info(f"Getting bulk users with permission {domain}.{iam_unit_type.value}.{permission_ref}")
|
|
363
|
+
try:
|
|
364
|
+
# This is a simplified implementation - in production, you would want to use
|
|
365
|
+
# Firestore queries to filter users with specific permissions rather than
|
|
366
|
+
# fetching all users. For now, we'll return an empty list and log a warning.
|
|
367
|
+
|
|
368
|
+
self.logger.warning(
|
|
369
|
+
"get_bulk_users_with_permission: This method requires database-level "
|
|
370
|
+
"querying for optimal performance. Current implementation is not "
|
|
371
|
+
"suitable for production use with large user bases."
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# TODO: Implement proper Firestore querying for users with specific permissions
|
|
375
|
+
# Example query structure:
|
|
376
|
+
# collection('userstatuses')
|
|
377
|
+
# .where('iam_permissions', 'array_contains', {
|
|
378
|
+
# 'domain': domain,
|
|
379
|
+
# 'iam_unit_type': iam_unit_type.value,
|
|
380
|
+
# 'permission_ref': permission_ref
|
|
381
|
+
# })
|
|
382
|
+
# .limit(limit)
|
|
383
|
+
|
|
384
|
+
return []
|
|
385
|
+
|
|
386
|
+
except Exception as e:
|
|
387
|
+
self.logger.error("Failed to get bulk users with permission: %s", e, exc_info=True)
|
|
388
|
+
raise IAMPermissionError(
|
|
389
|
+
detail=f"Failed to get bulk users with permission: {str(e)}",
|
|
390
|
+
operation="get_bulk_users_with_permission",
|
|
391
|
+
original_error=e
|
|
392
|
+
) from e
|