ipulse-shared-core-ftredge 20.0.1__py3-none-any.whl → 23.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.

Files changed (48) hide show
  1. ipulse_shared_core_ftredge/cache/shared_cache.py +1 -2
  2. ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +60 -23
  3. ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +128 -157
  4. ipulse_shared_core_ftredge/exceptions/base_exceptions.py +35 -4
  5. ipulse_shared_core_ftredge/models/__init__.py +3 -7
  6. ipulse_shared_core_ftredge/models/base_data_model.py +17 -19
  7. ipulse_shared_core_ftredge/models/catalog/__init__.py +10 -0
  8. ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +274 -0
  9. ipulse_shared_core_ftredge/models/catalog/usertype.py +177 -0
  10. ipulse_shared_core_ftredge/models/user/__init__.py +5 -0
  11. ipulse_shared_core_ftredge/models/user/user_permissions.py +66 -0
  12. ipulse_shared_core_ftredge/models/user/user_subscription.py +348 -0
  13. ipulse_shared_core_ftredge/models/{user_auth.py → user/userauth.py} +19 -10
  14. ipulse_shared_core_ftredge/models/{user_profile.py → user/userprofile.py} +53 -21
  15. ipulse_shared_core_ftredge/models/user/userstatus.py +479 -0
  16. ipulse_shared_core_ftredge/monitoring/__init__.py +0 -2
  17. ipulse_shared_core_ftredge/monitoring/tracemon.py +6 -6
  18. ipulse_shared_core_ftredge/services/__init__.py +11 -13
  19. ipulse_shared_core_ftredge/services/base/__init__.py +3 -1
  20. ipulse_shared_core_ftredge/services/base/base_firestore_service.py +77 -16
  21. ipulse_shared_core_ftredge/services/{cache_aware_firestore_service.py → base/cache_aware_firestore_service.py} +46 -32
  22. ipulse_shared_core_ftredge/services/catalog/__init__.py +14 -0
  23. ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +277 -0
  24. ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +376 -0
  25. ipulse_shared_core_ftredge/services/charging_processors.py +25 -25
  26. ipulse_shared_core_ftredge/services/user/__init__.py +5 -25
  27. ipulse_shared_core_ftredge/services/user/user_core_service.py +536 -510
  28. ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +796 -0
  29. ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +392 -0
  30. ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +488 -0
  31. ipulse_shared_core_ftredge/services/user/userauth_operations.py +928 -0
  32. ipulse_shared_core_ftredge/services/user/userprofile_operations.py +166 -0
  33. ipulse_shared_core_ftredge/services/user/userstatus_operations.py +476 -0
  34. ipulse_shared_core_ftredge/services/{charging_service.py → user_charging_service.py} +9 -9
  35. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/METADATA +3 -4
  36. ipulse_shared_core_ftredge-23.1.1.dist-info/RECORD +50 -0
  37. ipulse_shared_core_ftredge/models/subscription.py +0 -190
  38. ipulse_shared_core_ftredge/models/user_status.py +0 -495
  39. ipulse_shared_core_ftredge/monitoring/microservmon.py +0 -526
  40. ipulse_shared_core_ftredge/services/user/iam_management_operations.py +0 -326
  41. ipulse_shared_core_ftredge/services/user/subscription_management_operations.py +0 -384
  42. ipulse_shared_core_ftredge/services/user/user_account_operations.py +0 -479
  43. ipulse_shared_core_ftredge/services/user/user_auth_operations.py +0 -305
  44. ipulse_shared_core_ftredge/services/user/user_holistic_operations.py +0 -436
  45. ipulse_shared_core_ftredge-20.0.1.dist-info/RECORD +0 -42
  46. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/WHEEL +0 -0
  47. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/licenses/LICENCE +0 -0
  48. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/top_level.txt +0 -0
@@ -1,326 +0,0 @@
1
- """
2
- IAM Management Operations - Handle user permissions and access rights
3
- """
4
- import logging
5
- from typing import Dict, Any, Optional, List
6
- from datetime import datetime, timezone
7
- from ...models.user_status import IAMUnitRefAssignment
8
- from ipulse_shared_base_ftredge.enums.enums_status import ApprovalStatus
9
- from ipulse_shared_base_ftredge.enums.enums_iam import IAMUnitType
10
- from ...exceptions import IAMPermissionError, UserAuthError
11
-
12
-
13
- class IAMManagementOperations:
14
- """
15
- Handles IAM permissions and access rights management
16
- """
17
-
18
- def __init__(
19
- self,
20
- user_account_ops, # UserManagementOperations instance
21
- logger: Optional[logging.Logger] = None
22
- ):
23
- self.user_account_ops = user_account_ops
24
- self.logger = logger or logging.getLogger(__name__)
25
-
26
- # IAM Permission Operations
27
-
28
- async def add_user_permission(
29
- self,
30
- user_uid: str,
31
- domain: str,
32
- permission_name: str,
33
- iam_unit_type: IAMUnitType,
34
- source: str,
35
- expires_at: Optional[datetime] = None,
36
- updater_uid: Optional[str] = None
37
- ) -> bool:
38
- """Add an IAM permission to a user"""
39
- try:
40
- user_status = await self.user_account_ops.get_userstatus(user_uid)
41
- if not user_status:
42
- raise IAMPermissionError(
43
- detail="User status not found",
44
- user_uid=user_uid,
45
- domain=domain,
46
- permission=permission_name,
47
- operation="add_user_permission"
48
- )
49
-
50
- user_status.add_iam_unit_ref_assignment(
51
- domain=domain,
52
- iam_unit_ref=permission_name,
53
- iam_unit_type=iam_unit_type,
54
- source=source,
55
- expires_at=expires_at
56
- )
57
-
58
- user_status.updated_at = datetime.now(timezone.utc)
59
- user_status.updated_by = updater_uid or f"IAMManagement.add_permission:{source}"
60
-
61
- await self.user_account_ops.update_userstatus(
62
- user_uid=user_uid,
63
- status_data=user_status.model_dump(exclude_none=True),
64
- updater_uid=updater_uid or f"IAMManagement:{source}"
65
- )
66
-
67
- self.logger.info(f"Added {iam_unit_type.value} permission '{permission_name}' to user {user_uid} in domain '{domain}'")
68
- return True
69
-
70
- except Exception as e:
71
- self.logger.error(f"Error adding permission to user {user_uid}: {e}", exc_info=True)
72
- raise IAMPermissionError(
73
- detail=f"Failed to add permission: {str(e)}",
74
- user_uid=user_uid,
75
- domain=domain,
76
- permission=permission_name,
77
- operation="add_user_permission",
78
- original_error=e
79
- )
80
-
81
- async def remove_user_permission(
82
- self,
83
- user_uid: str,
84
- domain: str,
85
- permission_name: str,
86
- iam_unit_type: IAMUnitType,
87
- updater_uid: Optional[str] = None
88
- ) -> bool:
89
- """Remove an IAM permission from a user"""
90
- try:
91
- user_status = await self.user_account_ops.get_userstatus(user_uid)
92
- if not user_status:
93
- raise IAMPermissionError(
94
- detail="User status not found",
95
- user_uid=user_uid,
96
- domain=domain,
97
- permission=permission_name,
98
- operation="remove_user_permission"
99
- )
100
-
101
- # Check if permission exists
102
- if (domain not in user_status.iam_domain_permissions or
103
- iam_unit_type.value not in user_status.iam_domain_permissions[domain] or
104
- permission_name not in user_status.iam_domain_permissions[domain][iam_unit_type.value]):
105
- self.logger.warning(f"Permission '{permission_name}' not found for user {user_uid} in domain '{domain}'")
106
- return False
107
-
108
- # Remove the permission
109
- del user_status.iam_domain_permissions[domain][iam_unit_type.value][permission_name]
110
-
111
- # Clean up empty structures
112
- if not user_status.iam_domain_permissions[domain][iam_unit_type.value]:
113
- del user_status.iam_domain_permissions[domain][iam_unit_type.value]
114
- if not user_status.iam_domain_permissions[domain]:
115
- del user_status.iam_domain_permissions[domain]
116
-
117
- user_status.updated_at = datetime.now(timezone.utc)
118
- user_status.updated_by = updater_uid or "IAMManagement.remove_permission"
119
-
120
- await self.user_account_ops.update_userstatus(
121
- user_uid=user_uid,
122
- status_data=user_status.model_dump(exclude_none=True),
123
- updater_uid=updater_uid or "IAMManagement"
124
- )
125
-
126
- self.logger.info(f"Removed {iam_unit_type.value} permission '{permission_name}' from user {user_uid} in domain '{domain}'")
127
- return True
128
-
129
- except Exception as e:
130
- self.logger.error(f"Error removing permission from user {user_uid}: {e}", exc_info=True)
131
- raise IAMPermissionError(
132
- detail=f"Failed to remove permission: {str(e)}",
133
- user_uid=user_uid,
134
- domain=domain,
135
- permission=permission_name,
136
- operation="remove_user_permission",
137
- original_error=e
138
- )
139
-
140
- async def get_user_permissions(
141
- self,
142
- user_uid: str,
143
- domain: Optional[str] = None,
144
- iam_unit_type: Optional[IAMUnitType] = None,
145
- include_expired: bool = False
146
- ) -> Dict[str, Dict[str, Dict[str, IAMUnitRefAssignment]]]:
147
- """Get user's IAM permissions with optional filtering"""
148
- try:
149
- user_status = await self.user_account_ops.get_userstatus(user_uid)
150
- if not user_status:
151
- return {}
152
-
153
- permissions = user_status.iam_domain_permissions
154
-
155
- # Filter by domain if specified
156
- if domain:
157
- permissions = {domain: permissions.get(domain, {})}
158
-
159
- # Filter by IAM unit type if specified
160
- if iam_unit_type:
161
- filtered_permissions = {}
162
- for dom, domain_perms in permissions.items():
163
- if iam_unit_type.value in domain_perms:
164
- filtered_permissions[dom] = {iam_unit_type.value: domain_perms[iam_unit_type.value]}
165
- permissions = filtered_permissions
166
-
167
- # Filter expired permissions if requested
168
- if not include_expired:
169
- filtered_permissions = {}
170
- for dom, domain_perms in permissions.items():
171
- filtered_domain = {}
172
- for unit_type, unit_perms in domain_perms.items():
173
- filtered_unit = {
174
- perm_name: assignment
175
- for perm_name, assignment in unit_perms.items()
176
- if assignment.is_valid()
177
- }
178
- if filtered_unit:
179
- filtered_domain[unit_type] = filtered_unit
180
- if filtered_domain:
181
- filtered_permissions[dom] = filtered_domain
182
- permissions = filtered_permissions
183
-
184
- return permissions
185
-
186
- except Exception as e:
187
- self.logger.error(f"Error getting permissions for user {user_uid}: {e}", exc_info=True)
188
- raise IAMPermissionError(
189
- detail=f"Failed to get user permissions: {str(e)}",
190
- user_uid=user_uid,
191
- domain=domain,
192
- operation="get_user_permissions",
193
- original_error=e
194
- )
195
-
196
- async def has_user_permission(
197
- self,
198
- user_uid: str,
199
- domain: str,
200
- permission_name: str,
201
- iam_unit_type: IAMUnitType = IAMUnitType.GROUPS
202
- ) -> bool:
203
- """Check if user has a specific permission"""
204
- try:
205
- permissions = await self.get_user_permissions(
206
- user_uid=user_uid,
207
- domain=domain,
208
- iam_unit_type=iam_unit_type,
209
- include_expired=False
210
- )
211
-
212
- return (domain in permissions and
213
- iam_unit_type.value in permissions[domain] and
214
- permission_name in permissions[domain][iam_unit_type.value])
215
-
216
- except Exception as e:
217
- self.logger.error(f"Error checking permission for user {user_uid}: {e}", exc_info=True)
218
- return False
219
-
220
- async def cleanup_expired_permissions(self, user_uid: str, updater_uid: Optional[str] = None) -> int:
221
- """Remove all expired permissions for a user"""
222
- try:
223
- user_status = await self.user_account_ops.get_userstatus(user_uid)
224
- if not user_status:
225
- return 0
226
-
227
- removed_count = user_status.remove_expired_iam_unit_refs()
228
-
229
- if removed_count > 0:
230
- user_status.updated_at = datetime.now(timezone.utc)
231
- user_status.updated_by = updater_uid or "IAMManagement.cleanup_expired"
232
-
233
- await self.user_account_ops.update_userstatus(
234
- user_uid=user_uid,
235
- status_data=user_status.model_dump(exclude_none=True),
236
- updater_uid=updater_uid or "IAMManagement"
237
- )
238
-
239
- self.logger.info(f"Cleaned up {removed_count} expired permissions for user {user_uid}")
240
-
241
- return removed_count
242
-
243
- except Exception as e:
244
- self.logger.error(f"Error cleaning up expired permissions for user {user_uid}: {e}", exc_info=True)
245
- raise IAMPermissionError(
246
- detail=f"Failed to cleanup expired permissions: {str(e)}",
247
- user_uid=user_uid,
248
- operation="cleanup_expired_permissions",
249
- original_error=e
250
- )
251
-
252
- # Legacy group methods for backward compatibility
253
-
254
- async def add_user_group(
255
- self,
256
- user_uid: str,
257
- domain: str,
258
- group_name: str,
259
- source: str,
260
- expires_at: Optional[datetime] = None,
261
- updater_uid: Optional[str] = None
262
- ) -> bool:
263
- """Add a group to a user (legacy method)"""
264
- return await self.add_user_permission(
265
- user_uid=user_uid,
266
- domain=domain,
267
- permission_name=group_name,
268
- iam_unit_type=IAMUnitType.GROUPS,
269
- source=source,
270
- expires_at=expires_at,
271
- updater_uid=updater_uid
272
- )
273
-
274
- async def remove_user_group(
275
- self,
276
- user_uid: str,
277
- domain: str,
278
- group_name: str,
279
- updater_uid: Optional[str] = None
280
- ) -> bool:
281
- """Remove a group from a user (legacy method)"""
282
- return await self.remove_user_permission(
283
- user_uid=user_uid,
284
- domain=domain,
285
- permission_name=group_name,
286
- iam_unit_type=IAMUnitType.GROUPS,
287
- updater_uid=updater_uid
288
- )
289
-
290
- async def get_user_groups(
291
- self,
292
- user_uid: str,
293
- domain: Optional[str] = None,
294
- include_expired: bool = False
295
- ) -> Dict[str, Dict[str, IAMUnitRefAssignment]]:
296
- """Get user's groups (legacy method)"""
297
- permissions = await self.get_user_permissions(
298
- user_uid=user_uid,
299
- domain=domain,
300
- iam_unit_type=IAMUnitType.GROUPS,
301
- include_expired=include_expired
302
- )
303
-
304
- # Flatten to match legacy format
305
- groups = {}
306
- for domain_name, domain_perms in permissions.items():
307
- if IAMUnitType.GROUPS.value in domain_perms:
308
- groups[domain_name] = domain_perms[IAMUnitType.GROUPS.value]
309
-
310
- return groups
311
-
312
- async def has_user_group(
313
- self,
314
- user_uid: str,
315
- domain: str,
316
- group_name: str
317
- ) -> bool:
318
- """Check if user has a specific group (legacy method)"""
319
- return await self.has_user_permission(
320
- user_uid=user_uid,
321
- domain=domain,
322
- permission_name=group_name,
323
- iam_unit_type=IAMUnitType.GROUPS
324
- )
325
-
326
-