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.
- ipulse_shared_core_ftredge/cache/shared_cache.py +1 -2
- ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +60 -23
- ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +128 -157
- ipulse_shared_core_ftredge/exceptions/base_exceptions.py +35 -4
- 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 +274 -0
- ipulse_shared_core_ftredge/models/catalog/usertype.py +177 -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/user/user_subscription.py +348 -0
- 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 +479 -0
- ipulse_shared_core_ftredge/monitoring/__init__.py +0 -2
- ipulse_shared_core_ftredge/monitoring/tracemon.py +6 -6
- 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 +77 -16
- 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 +277 -0
- ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +376 -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/user_core_service.py +536 -510
- ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +796 -0
- ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +392 -0
- ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +488 -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 +476 -0
- ipulse_shared_core_ftredge/services/{charging_service.py → user_charging_service.py} +9 -9
- {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/METADATA +3 -4
- ipulse_shared_core_ftredge-23.1.1.dist-info/RECORD +50 -0
- ipulse_shared_core_ftredge/models/subscription.py +0 -190
- ipulse_shared_core_ftredge/models/user_status.py +0 -495
- ipulse_shared_core_ftredge/monitoring/microservmon.py +0 -526
- 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-20.0.1.dist-info/RECORD +0 -42
- {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/WHEEL +0 -0
- {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/licenses/LICENCE +0 -0
- {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/top_level.txt +0 -0
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
User Holistic Operations - Complete user lifecycle operations
|
|
3
|
-
|
|
4
|
-
Handles complete user creation and deletion operations that span across
|
|
5
|
-
Firebase Auth, UserProfile, and UserStatus in coordinated transactions.
|
|
6
|
-
"""
|
|
7
|
-
import logging
|
|
8
|
-
from typing import Dict, Any, Optional, Set, List, Tuple
|
|
9
|
-
from datetime import datetime, timezone
|
|
10
|
-
|
|
11
|
-
from ...models.user_profile import UserProfile
|
|
12
|
-
from ...models.user_status import UserStatus, IAMUnitRefAssignment
|
|
13
|
-
from ...models.user_auth import UserAuth
|
|
14
|
-
from .user_auth_operations import UserAuthOperations
|
|
15
|
-
from ...exceptions import (
|
|
16
|
-
UserCreationError
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class UserHolisticOperations:
|
|
21
|
-
"""
|
|
22
|
-
Handles complete user lifecycle operations including coordinated creation and deletion
|
|
23
|
-
of Firebase Auth users, UserProfile, and UserStatus documents.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
user_account_ops, # UserManagementOperations instance
|
|
29
|
-
user_auth_ops: Optional[UserAuthOperations] = None,
|
|
30
|
-
subscription_ops=None, # SubscriptionManagementOperations instance
|
|
31
|
-
iam_ops=None, # IAMManagementOperations instance
|
|
32
|
-
logger: Optional[logging.Logger] = None
|
|
33
|
-
):
|
|
34
|
-
self.user_account_ops = user_account_ops
|
|
35
|
-
self.user_auth_ops = user_auth_ops or UserAuthOperations(logger)
|
|
36
|
-
self.user_subscription_ops = subscription_ops
|
|
37
|
-
self.iam_ops = iam_ops
|
|
38
|
-
self.logger = logger or logging.getLogger(__name__)
|
|
39
|
-
|
|
40
|
-
# Complete User Creation
|
|
41
|
-
|
|
42
|
-
async def create_user(
|
|
43
|
-
self,
|
|
44
|
-
email: str,
|
|
45
|
-
primary_usertype: str,
|
|
46
|
-
password: Optional[str] = None,
|
|
47
|
-
organizations_uids: Optional[Set[str]] = None,
|
|
48
|
-
secondary_usertypes: Optional[List[str]] = None,
|
|
49
|
-
first_name: Optional[str] = None,
|
|
50
|
-
last_name: Optional[str] = None,
|
|
51
|
-
username: Optional[str] = None,
|
|
52
|
-
mobile: Optional[str] = None,
|
|
53
|
-
provider_id: str = "password",
|
|
54
|
-
email_verified: bool = False,
|
|
55
|
-
disabled: bool = False,
|
|
56
|
-
initial_subscription_plan_id: Optional[str] = None,
|
|
57
|
-
iam_domain_permissions: Optional[Dict[str, Dict[str, Dict[str, IAMUnitRefAssignment]]]] = None,
|
|
58
|
-
sbscrptn_based_insight_credits: int = 0,
|
|
59
|
-
extra_insight_credits: int = 0,
|
|
60
|
-
voting_credits: int = 0,
|
|
61
|
-
metadata: Optional[Dict[str, Any]] = None,
|
|
62
|
-
created_by: Optional[str] = None,
|
|
63
|
-
set_custom_claims: bool = True
|
|
64
|
-
) -> Tuple[str, UserProfile, UserStatus]:
|
|
65
|
-
"""
|
|
66
|
-
Create a complete user with Firebase Auth, UserProfile, and UserStatus
|
|
67
|
-
Returns: (user_uid, user_profile, user_status)
|
|
68
|
-
"""
|
|
69
|
-
user_uid = None
|
|
70
|
-
profile_created = False
|
|
71
|
-
status_created = False
|
|
72
|
-
|
|
73
|
-
try:
|
|
74
|
-
# Step 1: Create Firebase Auth user
|
|
75
|
-
self.logger.info(f"Creating Firebase Auth user for email: {email}")
|
|
76
|
-
user_auth = UserAuth(
|
|
77
|
-
email=email,
|
|
78
|
-
password=password,
|
|
79
|
-
email_verified=email_verified,
|
|
80
|
-
disabled=disabled,
|
|
81
|
-
phone_number=mobile
|
|
82
|
-
)
|
|
83
|
-
user_uid = await self.user_auth_ops.create_userauth(user_auth)
|
|
84
|
-
|
|
85
|
-
# Step 2: Create UserProfile
|
|
86
|
-
self.logger.info(f"Creating UserProfile for user: {user_uid}")
|
|
87
|
-
user_profile = UserProfile(
|
|
88
|
-
user_uid=user_uid,
|
|
89
|
-
primary_usertype=primary_usertype,
|
|
90
|
-
secondary_usertypes=secondary_usertypes or [],
|
|
91
|
-
email=email,
|
|
92
|
-
organizations_uids=organizations_uids or set(),
|
|
93
|
-
provider_id=provider_id,
|
|
94
|
-
username=username or "", # Will be auto-generated if empty
|
|
95
|
-
first_name=first_name,
|
|
96
|
-
last_name=last_name,
|
|
97
|
-
mobile=mobile,
|
|
98
|
-
metadata=metadata or {},
|
|
99
|
-
created_by=created_by
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
user_profile = await self.user_account_ops.create_userprofile(user_profile)
|
|
103
|
-
profile_created = True
|
|
104
|
-
|
|
105
|
-
# Step 3: Create UserStatus
|
|
106
|
-
self.logger.info(f"Creating UserStatus for user: {user_uid}")
|
|
107
|
-
user_status = await self.user_account_ops.create_userstatus(
|
|
108
|
-
user_uid=user_uid,
|
|
109
|
-
primary_usertype=primary_usertype,
|
|
110
|
-
organizations_uids=organizations_uids,
|
|
111
|
-
secondary_usertypes=secondary_usertypes,
|
|
112
|
-
initial_subscription_plan_id=initial_subscription_plan_id,
|
|
113
|
-
iam_domain_permissions=iam_domain_permissions or {},
|
|
114
|
-
sbscrptn_based_insight_credits=sbscrptn_based_insight_credits,
|
|
115
|
-
extra_insight_credits=extra_insight_credits,
|
|
116
|
-
voting_credits=voting_credits,
|
|
117
|
-
metadata=metadata,
|
|
118
|
-
created_by=created_by
|
|
119
|
-
)
|
|
120
|
-
status_created = True
|
|
121
|
-
|
|
122
|
-
# Step 4: Set Firebase custom claims if requested
|
|
123
|
-
if set_custom_claims:
|
|
124
|
-
self.logger.info(f"Setting Firebase custom claims for user: {user_uid}")
|
|
125
|
-
custom_claims = self.user_auth_ops.generate_firebase_custom_claims(
|
|
126
|
-
primary_usertype=primary_usertype,
|
|
127
|
-
secondary_usertypes=secondary_usertypes,
|
|
128
|
-
organizations_uids=list(organizations_uids) if organizations_uids else None
|
|
129
|
-
)
|
|
130
|
-
await self.user_auth_ops.set_userauth_custom_claims(user_uid, custom_claims)
|
|
131
|
-
|
|
132
|
-
self.logger.info(f"Successfully created complete user: {user_uid}")
|
|
133
|
-
return user_uid, user_profile, user_status
|
|
134
|
-
|
|
135
|
-
except Exception as e:
|
|
136
|
-
# Rollback on failure
|
|
137
|
-
await self._rollback_user_creation(
|
|
138
|
-
user_uid=user_uid,
|
|
139
|
-
profile_created=profile_created,
|
|
140
|
-
status_created=status_created,
|
|
141
|
-
error_context=f"Failed during complete user creation: {str(e)}"
|
|
142
|
-
)
|
|
143
|
-
raise UserCreationError(
|
|
144
|
-
detail=f"Failed to create complete user: {str(e)}",
|
|
145
|
-
email=email,
|
|
146
|
-
user_uid=user_uid,
|
|
147
|
-
original_error=e
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
async def create_user_from_auth_model(
|
|
151
|
-
self,
|
|
152
|
-
user_auth: UserAuth,
|
|
153
|
-
primary_usertype: str,
|
|
154
|
-
organizations_uids: Optional[Set[str]] = None,
|
|
155
|
-
secondary_usertypes: Optional[List[str]] = None,
|
|
156
|
-
first_name: Optional[str] = None,
|
|
157
|
-
last_name: Optional[str] = None,
|
|
158
|
-
username: Optional[str] = None,
|
|
159
|
-
initial_subscription_plan_id: Optional[str] = None,
|
|
160
|
-
created_by: Optional[str] = None
|
|
161
|
-
) -> Tuple[str, UserProfile, UserStatus]:
|
|
162
|
-
"""Create complete user from UserAuth model"""
|
|
163
|
-
return await self.create_user(
|
|
164
|
-
email=user_auth.email,
|
|
165
|
-
primary_usertype=primary_usertype,
|
|
166
|
-
password=user_auth.password,
|
|
167
|
-
organizations_uids=organizations_uids,
|
|
168
|
-
secondary_usertypes=secondary_usertypes,
|
|
169
|
-
first_name=first_name,
|
|
170
|
-
last_name=last_name,
|
|
171
|
-
username=username,
|
|
172
|
-
mobile=user_auth.phone_number,
|
|
173
|
-
provider_id=user_auth.provider_id,
|
|
174
|
-
email_verified=user_auth.email_verified,
|
|
175
|
-
disabled=user_auth.disabled,
|
|
176
|
-
initial_subscription_plan_id=initial_subscription_plan_id,
|
|
177
|
-
metadata=user_auth.metadata,
|
|
178
|
-
created_by=created_by,
|
|
179
|
-
set_custom_claims=bool(user_auth.custom_claims)
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
async def _rollback_user_creation(
|
|
183
|
-
self,
|
|
184
|
-
user_uid: Optional[str],
|
|
185
|
-
profile_created: bool,
|
|
186
|
-
status_created: bool,
|
|
187
|
-
error_context: str
|
|
188
|
-
) -> None:
|
|
189
|
-
"""Rollback user creation on failure"""
|
|
190
|
-
self.logger.error(f"Rolling back user creation: {error_context}")
|
|
191
|
-
|
|
192
|
-
if user_uid:
|
|
193
|
-
# Delete UserStatus if created
|
|
194
|
-
if status_created:
|
|
195
|
-
try:
|
|
196
|
-
await self.user_account_ops.delete_userstatus(user_uid, "rollback_deletion")
|
|
197
|
-
self.logger.info(f"Rolled back UserStatus creation for: {user_uid}")
|
|
198
|
-
except Exception as e:
|
|
199
|
-
self.logger.error(f"Failed to rollback UserStatus creation: {e}")
|
|
200
|
-
|
|
201
|
-
# Delete UserProfile if created
|
|
202
|
-
if profile_created:
|
|
203
|
-
try:
|
|
204
|
-
await self.user_account_ops.delete_userprofile(user_uid, "rollback_deletion")
|
|
205
|
-
self.logger.info(f"Rolled back UserProfile creation for: {user_uid}")
|
|
206
|
-
except Exception as e:
|
|
207
|
-
self.logger.error(f"Failed to rollback UserProfile creation: {e}")
|
|
208
|
-
|
|
209
|
-
# Delete Firebase Auth user
|
|
210
|
-
try:
|
|
211
|
-
await self.user_auth_ops.delete_userauth(user_uid)
|
|
212
|
-
self.logger.info(f"Rolled back Firebase Auth user creation for: {user_uid}")
|
|
213
|
-
except Exception as e:
|
|
214
|
-
self.logger.error(f"Failed to rollback Firebase Auth user creation: {e}")
|
|
215
|
-
|
|
216
|
-
# Complete User Deletion
|
|
217
|
-
|
|
218
|
-
async def delete_user(
|
|
219
|
-
self,
|
|
220
|
-
user_uid: str,
|
|
221
|
-
delete_auth_user: bool = True,
|
|
222
|
-
delete_profile: bool = True,
|
|
223
|
-
delete_status: bool = True,
|
|
224
|
-
deleted_by: str = "system_complete_deletion"
|
|
225
|
-
) -> Dict[str, Any]:
|
|
226
|
-
"""
|
|
227
|
-
Delete complete user including Firebase Auth, UserProfile, and UserStatus
|
|
228
|
-
with proper archival and error handling
|
|
229
|
-
"""
|
|
230
|
-
results = {
|
|
231
|
-
"user_uid": user_uid,
|
|
232
|
-
"auth_deleted_successfully": False,
|
|
233
|
-
"profile_deleted_successfully": False,
|
|
234
|
-
"status_deleted_successfully": False,
|
|
235
|
-
"errors": [],
|
|
236
|
-
"deleted_by": deleted_by,
|
|
237
|
-
"deleted_at": datetime.now(timezone.utc).isoformat()
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
# Step 1: Delete UserProfile (with archival)
|
|
241
|
-
if delete_profile:
|
|
242
|
-
try:
|
|
243
|
-
profile_deleted = await self.user_account_ops.delete_userprofile(user_uid, deleted_by)
|
|
244
|
-
results["profile_deleted_successfully"] = profile_deleted
|
|
245
|
-
if profile_deleted:
|
|
246
|
-
self.logger.info(f"Successfully deleted UserProfile for user: {user_uid}")
|
|
247
|
-
except Exception as e:
|
|
248
|
-
error_msg = f"Failed to delete UserProfile: {str(e)}"
|
|
249
|
-
self.logger.error(error_msg, exc_info=True)
|
|
250
|
-
results["errors"].append(error_msg)
|
|
251
|
-
|
|
252
|
-
# Step 2: Delete UserStatus (with archival)
|
|
253
|
-
if delete_status:
|
|
254
|
-
try:
|
|
255
|
-
status_deleted = await self.user_account_ops.delete_userstatus(user_uid, deleted_by)
|
|
256
|
-
results["status_deleted_successfully"] = status_deleted
|
|
257
|
-
if status_deleted:
|
|
258
|
-
self.logger.info(f"Successfully deleted UserStatus for user: {user_uid}")
|
|
259
|
-
except Exception as e:
|
|
260
|
-
error_msg = f"Failed to delete UserStatus: {str(e)}"
|
|
261
|
-
self.logger.error(error_msg, exc_info=True)
|
|
262
|
-
results["errors"].append(error_msg)
|
|
263
|
-
|
|
264
|
-
# Step 3: Delete Firebase Auth user
|
|
265
|
-
if delete_auth_user:
|
|
266
|
-
try:
|
|
267
|
-
auth_deleted = await self.user_auth_ops.delete_userauth(user_uid)
|
|
268
|
-
results["auth_deleted_successfully"] = auth_deleted
|
|
269
|
-
if auth_deleted:
|
|
270
|
-
self.logger.info(f"Successfully deleted Firebase Auth user: {user_uid}")
|
|
271
|
-
except Exception as e:
|
|
272
|
-
error_msg = f"Failed to delete Firebase Auth user: {str(e)}"
|
|
273
|
-
self.logger.error(error_msg, exc_info=True)
|
|
274
|
-
results["errors"].append(error_msg)
|
|
275
|
-
|
|
276
|
-
# Determine overall success
|
|
277
|
-
total_operations = sum([delete_auth_user, delete_profile, delete_status])
|
|
278
|
-
successful_operations = sum([
|
|
279
|
-
results["auth_deleted_successfully"] if delete_auth_user else True,
|
|
280
|
-
results["profile_deleted_successfully"] if delete_profile else True,
|
|
281
|
-
results["status_deleted_successfully"] if delete_status else True
|
|
282
|
-
])
|
|
283
|
-
|
|
284
|
-
results["overall_success"] = successful_operations == total_operations
|
|
285
|
-
results["partial_success"] = successful_operations > 0
|
|
286
|
-
|
|
287
|
-
if results["overall_success"]:
|
|
288
|
-
self.logger.info(f"Successfully completed full deletion of user: {user_uid}")
|
|
289
|
-
elif results["partial_success"]:
|
|
290
|
-
self.logger.warning(f"Partial deletion completed for user {user_uid}. Errors: {results['errors']}")
|
|
291
|
-
else:
|
|
292
|
-
self.logger.error(f"Failed to delete user {user_uid}. Errors: {results['errors']}")
|
|
293
|
-
|
|
294
|
-
return results
|
|
295
|
-
|
|
296
|
-
async def batch_delete_users(
|
|
297
|
-
self,
|
|
298
|
-
user_uids: List[str],
|
|
299
|
-
delete_auth_user: bool = True,
|
|
300
|
-
deleted_by: str = "system_batch_complete_deletion"
|
|
301
|
-
) -> Dict[str, Dict[str, Any]]:
|
|
302
|
-
"""
|
|
303
|
-
Batch delete multiple complete users
|
|
304
|
-
Returns dictionary with user_uid as key and deletion result as value
|
|
305
|
-
"""
|
|
306
|
-
results = {}
|
|
307
|
-
|
|
308
|
-
for user_uid in user_uids:
|
|
309
|
-
try:
|
|
310
|
-
result = await self.delete_user(
|
|
311
|
-
user_uid=user_uid,
|
|
312
|
-
delete_auth_user=delete_auth_user,
|
|
313
|
-
deleted_by=deleted_by
|
|
314
|
-
)
|
|
315
|
-
results[user_uid] = result
|
|
316
|
-
except Exception as e:
|
|
317
|
-
self.logger.error(f"Failed to delete user {user_uid}: {e}", exc_info=True)
|
|
318
|
-
results[user_uid] = {
|
|
319
|
-
"user_uid": user_uid,
|
|
320
|
-
"auth_deleted_successfully": False,
|
|
321
|
-
"profile_deleted_successfully": False,
|
|
322
|
-
"status_deleted_successfully": False,
|
|
323
|
-
"errors": [f"Batch deletion failed: {str(e)}"],
|
|
324
|
-
"overall_success": False,
|
|
325
|
-
"partial_success": False,
|
|
326
|
-
"deleted_by": deleted_by,
|
|
327
|
-
"deleted_at": datetime.now(timezone.utc).isoformat()
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return results
|
|
331
|
-
|
|
332
|
-
# Document-level batch operations
|
|
333
|
-
|
|
334
|
-
async def batch_delete_user_core_docs(
|
|
335
|
-
self,
|
|
336
|
-
user_uids: List[str],
|
|
337
|
-
deleted_by: str = "system_batch_deletion"
|
|
338
|
-
) -> Dict[str, Tuple[bool, bool, Optional[str]]]:
|
|
339
|
-
"""Batch delete multiple users' documents (profile and status only)"""
|
|
340
|
-
batch_results: Dict[str, Tuple[bool, bool, Optional[str]]] = {}
|
|
341
|
-
|
|
342
|
-
# Process sequentially to avoid overwhelming the database
|
|
343
|
-
for user_uid in user_uids:
|
|
344
|
-
self.logger.info(f"Batch deletion: Processing user_uid: {user_uid}")
|
|
345
|
-
item_deleted_by = f"{deleted_by}_batch_item_{user_uid}"
|
|
346
|
-
|
|
347
|
-
try:
|
|
348
|
-
# Use delete_user but only for documents, not auth
|
|
349
|
-
result = await self.delete_user(
|
|
350
|
-
user_uid=user_uid,
|
|
351
|
-
delete_auth_user=False, # Only delete documents
|
|
352
|
-
delete_profile=True,
|
|
353
|
-
delete_status=True,
|
|
354
|
-
deleted_by=item_deleted_by
|
|
355
|
-
)
|
|
356
|
-
|
|
357
|
-
batch_results[user_uid] = (
|
|
358
|
-
result["profile_deleted_successfully"],
|
|
359
|
-
result["status_deleted_successfully"],
|
|
360
|
-
result["errors"][0] if result["errors"] else None
|
|
361
|
-
)
|
|
362
|
-
except Exception as e:
|
|
363
|
-
self.logger.error(f"Batch deletion failed for user {user_uid}: {e}", exc_info=True)
|
|
364
|
-
batch_results[user_uid] = (False, False, str(e))
|
|
365
|
-
|
|
366
|
-
return batch_results
|
|
367
|
-
|
|
368
|
-
# User Restoration
|
|
369
|
-
|
|
370
|
-
async def restore_user_account_docs_from_archive(
|
|
371
|
-
self,
|
|
372
|
-
user_uid: str,
|
|
373
|
-
restore_profile: bool = True,
|
|
374
|
-
restore_status: bool = True,
|
|
375
|
-
restored_by: str = "system_restore"
|
|
376
|
-
) -> Dict[str, bool]:
|
|
377
|
-
"""
|
|
378
|
-
Restore complete user from archive (does not restore Firebase Auth user)
|
|
379
|
-
Firebase Auth user needs to be recreated separately
|
|
380
|
-
"""
|
|
381
|
-
results = {
|
|
382
|
-
"profile_restored": False,
|
|
383
|
-
"status_restored": False
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if restore_profile:
|
|
387
|
-
try:
|
|
388
|
-
results["profile_restored"] = await self.user_account_ops.restore_userprofile_from_archive(
|
|
389
|
-
user_uid, restored_by
|
|
390
|
-
)
|
|
391
|
-
except Exception as e:
|
|
392
|
-
self.logger.error(f"Failed to restore UserProfile for {user_uid}: {e}", exc_info=True)
|
|
393
|
-
|
|
394
|
-
if restore_status:
|
|
395
|
-
try:
|
|
396
|
-
results["status_restored"] = await self.user_account_ops.restore_userstatus_from_archive(
|
|
397
|
-
user_uid, restored_by
|
|
398
|
-
)
|
|
399
|
-
except Exception as e:
|
|
400
|
-
self.logger.error(f"Failed to restore UserStatus for {user_uid}: {e}", exc_info=True)
|
|
401
|
-
|
|
402
|
-
return results
|
|
403
|
-
|
|
404
|
-
# Utility Methods
|
|
405
|
-
|
|
406
|
-
async def user_exists_fully(self, user_uid: str) -> Dict[str, bool]:
|
|
407
|
-
"""Check if complete user exists (Auth, Profile, Status)"""
|
|
408
|
-
return {
|
|
409
|
-
"auth_exists": await self.user_auth_ops.userauth_exists(user_uid),
|
|
410
|
-
"profile_exists": (await self.user_account_ops.get_userprofile(user_uid)) is not None,
|
|
411
|
-
"status_exists": (await self.user_account_ops.get_userstatus(user_uid)) is not None
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async def validate_user_full_existance(self, user_uid: str) -> Dict[str, Any]:
|
|
415
|
-
"""Validate complete user integrity"""
|
|
416
|
-
existence = await self.user_exists_fully(user_uid)
|
|
417
|
-
|
|
418
|
-
validation_results = {
|
|
419
|
-
"user_uid": user_uid,
|
|
420
|
-
"exists": existence,
|
|
421
|
-
"is_complete": all(existence.values()),
|
|
422
|
-
"missing_components": [k for k, v in existence.items() if not v],
|
|
423
|
-
"validation_errors": []
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
# Additional validation for existing components
|
|
427
|
-
if existence["auth_exists"]:
|
|
428
|
-
try:
|
|
429
|
-
auth_valid = await self.user_auth_ops.validate_userauth(user_uid)
|
|
430
|
-
validation_results["auth_valid"] = auth_valid
|
|
431
|
-
if not auth_valid:
|
|
432
|
-
validation_results["validation_errors"].append("Firebase Auth user is disabled")
|
|
433
|
-
except Exception as e:
|
|
434
|
-
validation_results["validation_errors"].append(f"Auth validation error: {str(e)}")
|
|
435
|
-
|
|
436
|
-
return validation_results
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
ipulse_shared_core_ftredge/__init__.py,sha256=-KbdF_YW8pgf7pVv9qh_cA1xrNm_B9zigHYDo7ZA4eU,42
|
|
2
|
-
ipulse_shared_core_ftredge/cache/__init__.py,sha256=i2fPojmZiBwAoY5ovnnnME9USl4bi8MRPYkAgEfACfI,136
|
|
3
|
-
ipulse_shared_core_ftredge/cache/shared_cache.py,sha256=NMHSQyHjhn11IB3cQjw7ctV18CXBT1X6FC2UvURtBy8,12957
|
|
4
|
-
ipulse_shared_core_ftredge/dependencies/__init__.py,sha256=HGsR8HUguKTfjz_BorCILS4izX8CAjG-apE0kIPE0Yo,68
|
|
5
|
-
ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py,sha256=EFWyhoVOI0tGYOWqN5St4JNIy4cMwpxeBhKdjOwEfbg,1888
|
|
6
|
-
ipulse_shared_core_ftredge/dependencies/auth_protected_router.py,sha256=em5D5tE7OkgZmuCtYCKuUAnIZCgRJhCF8Ye5QmtGWlk,1807
|
|
7
|
-
ipulse_shared_core_ftredge/dependencies/authz_for_apis.py,sha256=6mJwk_xJILbnvPDfnxXyCebvP9TymvK0NaEDT8KBU-A,15826
|
|
8
|
-
ipulse_shared_core_ftredge/dependencies/firestore_client.py,sha256=VbTb121nsc9EZPd1RDEsHBLW5pIiVw6Wdo2JFL4afMg,714
|
|
9
|
-
ipulse_shared_core_ftredge/exceptions/__init__.py,sha256=Cb_RsIie4DbT_NLwFVwjw4riDKsNNRQEuAvHvYa-Zco,1038
|
|
10
|
-
ipulse_shared_core_ftredge/exceptions/base_exceptions.py,sha256=1aauMfq0t39nETXpJwD_kcry4Mih_2s_EwcIrMVyCCk,4294
|
|
11
|
-
ipulse_shared_core_ftredge/exceptions/user_exceptions.py,sha256=I-nm21MKrUYEoybpRODeYNzc184HfgHvRZQm_xux4VY,6824
|
|
12
|
-
ipulse_shared_core_ftredge/models/__init__.py,sha256=V9X0iqZXLp5x7O04pFGGgMvuc2Q8AozoTxqXS7utkQU,351
|
|
13
|
-
ipulse_shared_core_ftredge/models/base_api_response.py,sha256=OwuWI2PsMSLDkFt643u35ZhW5AHFEMMAGnGprmUO0fA,2380
|
|
14
|
-
ipulse_shared_core_ftredge/models/base_data_model.py,sha256=iVEYNk_P2FHZ0vgaAU0I34noWe3OsFJTr0YepRcRT78,2580
|
|
15
|
-
ipulse_shared_core_ftredge/models/subscription.py,sha256=bu6BtyDQ4jDkK3PLY97dZ_A3cmjzZahTkuaFOFybdxI,6892
|
|
16
|
-
ipulse_shared_core_ftredge/models/user_auth.py,sha256=NLR3Fazj4ZKy-ym8utnfhwDbxHExsb4DVqFZ2xI4kLI,3140
|
|
17
|
-
ipulse_shared_core_ftredge/models/user_profile.py,sha256=lqpuXfdXFm-yw5xnwk_BC6QLxpBKbxaED0q2_6-GBvw,5765
|
|
18
|
-
ipulse_shared_core_ftredge/models/user_status.py,sha256=7t3aY4-FjC_Jm2NVIlV-88zcdOG9Bd_g3c5Vpt-amSw,21077
|
|
19
|
-
ipulse_shared_core_ftredge/monitoring/__init__.py,sha256=lH1zGVWMuWkqh6mmBWq0GU2pdbg7lfdBXHckGlf768k,120
|
|
20
|
-
ipulse_shared_core_ftredge/monitoring/microservmon.py,sha256=hg713JDW-QGXvBlHIP--nBKF94XcWzcHCOjmkr87BrA,21031
|
|
21
|
-
ipulse_shared_core_ftredge/monitoring/tracemon.py,sha256=92a6hWhMB1nAqfKG0pCW3sBqfEHLNitInNI9O-zyv-8,11616
|
|
22
|
-
ipulse_shared_core_ftredge/services/__init__.py,sha256=HbPhpzeJjf0_B7IjfbqA1DcRb2b3ZEvdL_axx173Yh4,894
|
|
23
|
-
ipulse_shared_core_ftredge/services/cache_aware_firestore_service.py,sha256=QCDU8Xy3ztEMy9wLzoZmszQp6J7m5wEcNki2JPDWqyI,9140
|
|
24
|
-
ipulse_shared_core_ftredge/services/charging_processors.py,sha256=8bozatlie8egZFA-IUc2Vh1zjhyTdDqoe5nNgsL_ebM,16170
|
|
25
|
-
ipulse_shared_core_ftredge/services/charging_service.py,sha256=WG4Z4DnSV0VnIr5WJfu1IdfPY0roDnv-AW2sWUcB1H4,14641
|
|
26
|
-
ipulse_shared_core_ftredge/services/base/__init__.py,sha256=Dnr7unqPmOHadxLXZRXF207QI_x3GPjU4zIvc9Ltmag,285
|
|
27
|
-
ipulse_shared_core_ftredge/services/base/base_firestore_service.py,sha256=MPmH5CBZ24f2S-3v7MGML58xcnVd5XIPFMh1UmgOyJE,16752
|
|
28
|
-
ipulse_shared_core_ftredge/services/user/__init__.py,sha256=pi3s988J727poHUffydi067GrSvE7ZPH2Y8MPbtw9eE,1354
|
|
29
|
-
ipulse_shared_core_ftredge/services/user/iam_management_operations.py,sha256=sq72mFUlRBxGK8fseWOYngcoP2zaY5ye2cXWwlMA9J8,12236
|
|
30
|
-
ipulse_shared_core_ftredge/services/user/subscription_management_operations.py,sha256=3dnABXGxEIKT3YKd-Ffq0MD9qpA_Nq6nt46_XOi4ZjI,17382
|
|
31
|
-
ipulse_shared_core_ftredge/services/user/user_account_operations.py,sha256=INlOHXtA_8SJmNwrH_IpIDTVWd-60MkBBEdR6WyPUjg,19900
|
|
32
|
-
ipulse_shared_core_ftredge/services/user/user_auth_operations.py,sha256=fIPIz9Er_sT6pA0NK0cLns96I-a_1-vYQMbJTcFp7t8,11522
|
|
33
|
-
ipulse_shared_core_ftredge/services/user/user_core_service.py,sha256=6ohzMI2rBhDsx7wibeR4rhFkgsudM4a5mrkO-B1ED30,29122
|
|
34
|
-
ipulse_shared_core_ftredge/services/user/user_holistic_operations.py,sha256=oujCe6E3DIYTzfxrB7bbU97CbnFJVxmgM9cm-16JILI,18090
|
|
35
|
-
ipulse_shared_core_ftredge/utils/__init__.py,sha256=JnxUb8I2MRjJC7rBPXSrpwBIQDEOku5O9JsiTi3oun8,56
|
|
36
|
-
ipulse_shared_core_ftredge/utils/custom_json_encoder.py,sha256=DblQLD0KOSNDyQ58wQRogBrShIXzPIZUw_oGOBATnJY,1366
|
|
37
|
-
ipulse_shared_core_ftredge/utils/json_encoder.py,sha256=QkcaFneVv3-q-s__Dz4OiUWYnM6jgHDJrDMdPv09RCA,2093
|
|
38
|
-
ipulse_shared_core_ftredge-20.0.1.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
|
|
39
|
-
ipulse_shared_core_ftredge-20.0.1.dist-info/METADATA,sha256=Yw11hvsKpLro4hxINzgUgcqzuBIwM-pThiAzkGsarbU,803
|
|
40
|
-
ipulse_shared_core_ftredge-20.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
41
|
-
ipulse_shared_core_ftredge-20.0.1.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
|
|
42
|
-
ipulse_shared_core_ftredge-20.0.1.dist-info/RECORD,,
|
{ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|