ipulse-shared-core-ftredge 22.1.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 (20) hide show
  1. ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +60 -23
  2. ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +128 -157
  3. ipulse_shared_core_ftredge/exceptions/base_exceptions.py +12 -4
  4. ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +4 -3
  5. ipulse_shared_core_ftredge/models/catalog/usertype.py +8 -1
  6. ipulse_shared_core_ftredge/models/user/user_subscription.py +142 -30
  7. ipulse_shared_core_ftredge/models/user/userstatus.py +63 -14
  8. ipulse_shared_core_ftredge/services/base/base_firestore_service.py +5 -3
  9. ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +27 -23
  10. ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +94 -25
  11. ipulse_shared_core_ftredge/services/user/user_core_service.py +141 -23
  12. ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +144 -74
  13. ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +24 -20
  14. ipulse_shared_core_ftredge/services/user/userstatus_operations.py +268 -4
  15. {ipulse_shared_core_ftredge-22.1.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/METADATA +1 -1
  16. {ipulse_shared_core_ftredge-22.1.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/RECORD +19 -20
  17. ipulse_shared_core_ftredge/services/user/firebase_auth_admin_helpers.py +0 -160
  18. {ipulse_shared_core_ftredge-22.1.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/WHEEL +0 -0
  19. {ipulse_shared_core_ftredge-22.1.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/licenses/LICENCE +0 -0
  20. {ipulse_shared_core_ftredge-22.1.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
2
2
  Subscription Management Operations - Handle user subscriptions and related operations
3
3
  """
4
4
  import logging
5
- from typing import Optional
5
+ from typing import Optional, Dict, Any
6
6
  from datetime import datetime, timezone
7
7
  from google.cloud import firestore
8
8
  from google.cloud.exceptions import GoogleCloudError
@@ -32,12 +32,12 @@ class UsersubscriptionOperations:
32
32
  self.logger = logger or logging.getLogger(__name__)
33
33
  self.timeout = timeout
34
34
 
35
- def _create_subscription_from_subscriptionplan(
35
+ def create_subscription_from_subscriptionplan(
36
36
  self,
37
37
  plan: SubscriptionPlan,
38
38
  source: str,
39
39
  granted_at: Optional[datetime] = None,
40
- auto_renewal: Optional[bool] = None
40
+ auto_renewal_end: Optional[datetime] = None
41
41
  ) -> UserSubscription:
42
42
  """
43
43
  Common helper function to create a UserSubscription from a SubscriptionPlan.
@@ -68,10 +68,8 @@ class UsersubscriptionOperations:
68
68
  plan.plan_validity_cycle_unit
69
69
  )
70
70
 
71
- # Use provided auto_renewal or default from plan
72
- effective_auto_renewal = auto_renewal if auto_renewal is not None else (
73
- plan.plan_default_auto_renewal if plan.plan_default_auto_renewal is not None else False
74
- )
71
+ # Use provided auto_renewal_end or default from plan
72
+ effective_auto_renewal_end = auto_renewal_end if auto_renewal_end is not None else plan.plan_default_auto_renewal_end
75
73
 
76
74
  try:
77
75
  # Validate plan name
@@ -89,10 +87,10 @@ class UsersubscriptionOperations:
89
87
  plan_version=plan.plan_version,
90
88
  plan_id=plan.id or f"{plan.plan_name}_{plan.plan_version}",
91
89
  cycle_start_date=start_date,
92
- cycle_end_date=end_date,
90
+ cycle_end_datetime=end_date,
93
91
  validity_time_length=plan.plan_validity_cycle_length,
94
92
  validity_time_unit=plan.plan_validity_cycle_unit,
95
- auto_renew=effective_auto_renewal,
93
+ auto_renew_end_datetime=effective_auto_renewal_end,
96
94
  status=SubscriptionStatus.ACTIVE,
97
95
  granted_iam_permissions=plan.granted_iam_permissions or [],
98
96
  fallback_plan_id=plan.fallback_plan_id_if_current_plan_expired,
@@ -113,7 +111,7 @@ class UsersubscriptionOperations:
113
111
  updater_uid: str,
114
112
  source: str = "system_default_config",
115
113
  granted_at: Optional[datetime] = None,
116
- auto_renewal: Optional[bool] = None
114
+ auto_renewal_end: Optional[datetime] = None
117
115
  ) -> UserSubscription:
118
116
  """
119
117
  Fetch a subscription plan from catalog service and apply to user.
@@ -124,7 +122,7 @@ class UsersubscriptionOperations:
124
122
  updater_uid: Who is applying the subscription
125
123
  source: Source identifier
126
124
  granted_at: Optional granted timestamp (overrides plan defaults)
127
- auto_renewal: Optional auto-renewal setting (overrides plan defaults)
125
+ auto_renewal_end: Optional auto-renewal end date (overrides plan defaults)
128
126
 
129
127
  Returns:
130
128
  Applied UserSubscription
@@ -158,7 +156,7 @@ class UsersubscriptionOperations:
158
156
  updater_uid=updater_uid,
159
157
  source=source,
160
158
  granted_at=granted_at,
161
- auto_renewal=auto_renewal,
159
+ auto_renewal_end=auto_renewal_end,
162
160
  add_associated_permissions=True
163
161
  )
164
162
 
@@ -182,7 +180,7 @@ class UsersubscriptionOperations:
182
180
  updater_uid: str,
183
181
  source: str = "system_default_config",
184
182
  granted_at: Optional[datetime] = None,
185
- auto_renewal: Optional[bool] = None,
183
+ auto_renewal_end: Optional[datetime] = None,
186
184
  add_associated_permissions: bool = True
187
185
  ) -> UserSubscription:
188
186
  """
@@ -213,18 +211,18 @@ class UsersubscriptionOperations:
213
211
 
214
212
  try:
215
213
  # Create subscription from plan using helper
216
- subscription = self._create_subscription_from_subscriptionplan(
214
+ subscription = self.create_subscription_from_subscriptionplan(
217
215
  plan=subscriptionplan,
218
216
  source=f"{source}:{updater_uid}",
219
217
  granted_at=granted_at,
220
- auto_renewal=auto_renewal
218
+ auto_renewal_end=auto_renewal_end
221
219
  )
222
220
 
223
221
  # Apply subscription to user (this will handle removing existing permissions and adding new ones)
224
222
  permissions_added = userstatus.apply_subscription(
225
223
  subscription,
226
224
  add_associated_permissions=add_associated_permissions,
227
- remove_existing_subscription_permissions=True,
225
+ remove_previous_subscription_permissions=True,
228
226
  granted_by=f"UsersubscriptionOperations.apply:{source}:{updater_uid}"
229
227
  )
230
228
 
@@ -442,18 +440,18 @@ class UsersubscriptionOperations:
442
440
  current_plan_id = userstatus.active_subscription.plan_id
443
441
 
444
442
  # Create new subscription from fallback plan with updated granted_at
445
- new_subscription = self._create_subscription_from_subscriptionplan(
443
+ new_subscription = self.create_subscription_from_subscriptionplan(
446
444
  plan=fallback_plan,
447
445
  source=f"downgrade_from_{current_plan_id}:{reason}",
448
446
  granted_at=datetime.now(timezone.utc), # Set to now for downgrade
449
- auto_renewal=fallback_plan.plan_default_auto_renewal
447
+ auto_renewal_end=fallback_plan.plan_default_auto_renewal_end
450
448
  )
451
449
 
452
450
  # Apply the new subscription to user (this will handle revoking existing permissions and adding new ones)
453
451
  permissions_added = userstatus.apply_subscription(
454
452
  new_subscription,
455
453
  add_associated_permissions=True,
456
- remove_existing_subscription_permissions=True,
454
+ remove_previous_subscription_permissions=True,
457
455
  granted_by=f"UsersubscriptionOperations:downgrade:{reason}"
458
456
  )
459
457
  userstatus.updated_at = datetime.now(timezone.utc)
@@ -481,4 +479,10 @@ class UsersubscriptionOperations:
481
479
  plan_id=fallback_plan_id,
482
480
  operation="downgrade_to_fallback_plan",
483
481
  original_error=e
484
- ) from e
482
+ ) from e
483
+
484
+ ######################################################################
485
+ ######################### Subscription Lifecycle Support Methods #####
486
+ ######################################################################
487
+ # Note: The main review method has been moved to UserStatusOperations
488
+ # as it manages overall user status, not just subscriptions
@@ -3,7 +3,7 @@ Userstatus Operations - CRUD operations for Userstatus
3
3
  """
4
4
  import os
5
5
  import logging
6
- from typing import Dict, Any, Optional
6
+ from typing import Dict, Any, Optional, TYPE_CHECKING
7
7
 
8
8
  from google.cloud import firestore
9
9
  from pydantic import ValidationError as PydanticValidationError
@@ -12,6 +12,11 @@ from ...models import UserStatus
12
12
  from ...exceptions import ResourceNotFoundError, UserStatusError
13
13
  from ..base import BaseFirestoreService
14
14
 
15
+ # Type checking imports to avoid circular dependencies
16
+ if TYPE_CHECKING:
17
+ from .user_subscription_operations import UsersubscriptionOperations
18
+ from .user_permissions_operations import UserpermissionsOperations
19
+
15
20
 
16
21
  class UserstatusOperations:
17
22
  """
@@ -23,12 +28,18 @@ class UserstatusOperations:
23
28
  firestore_client: firestore.Client,
24
29
  logger: Optional[logging.Logger] = None,
25
30
  timeout: float = 10.0,
26
- status_collection: Optional[str] = None
31
+ status_collection: Optional[str] = None,
32
+ subscription_ops: Optional["UsersubscriptionOperations"] = None,
33
+ permissions_ops: Optional["UserpermissionsOperations"] = None
27
34
  ):
28
35
  self.db = firestore_client
29
36
  self.logger = logger or logging.getLogger(__name__)
30
37
  self.timeout = timeout
31
38
 
39
+ # Optional dependencies for comprehensive operations
40
+ self.subscription_ops = subscription_ops
41
+ self.permissions_ops = permissions_ops
42
+
32
43
  self.status_collection_name = status_collection or UserStatus.get_collection_name()
33
44
 
34
45
  # Archival configuration
@@ -110,8 +121,8 @@ class UserstatusOperations:
110
121
 
111
122
  try:
112
123
  updated_doc_dict = await self._status_db_service.update_document(
113
- userstatus_id,
114
- update_data,
124
+ doc_id=userstatus_id,
125
+ update_data=update_data,
115
126
  updater_uid=updater_uid
116
127
  )
117
128
  self.logger.info("Userstatus for %s updated successfully by %s", user_uid, updater_uid)
@@ -210,3 +221,256 @@ class UserstatusOperations:
210
221
  async def userstatus_exists(self, user_uid: str) -> bool:
211
222
  """Check if a user status exists."""
212
223
  return await self._status_db_service.document_exists(f"{UserStatus.OBJ_REF}_{user_uid}")
224
+
225
+ ######################################################################
226
+ ######################### Comprehensive Review Methods #############
227
+ ######################################################################
228
+
229
+ async def review_and_clean_active_subscription_credits_and_permissions(
230
+ self,
231
+ user_uid: str,
232
+ updater_uid: str = "system_review",
233
+ review_auto_renewal: bool = True,
234
+ apply_fallback: bool = True,
235
+ clean_expired_permissions: bool = True,
236
+ review_credits: bool = True
237
+ ) -> Dict[str, Any]:
238
+ """
239
+ Comprehensive review of user's active subscription, credits, and permissions.
240
+ This method handles:
241
+ 1. Subscription lifecycle (auto-renewal, fallback, expiration)
242
+ 2. Credit management based on subscription cycle timing
243
+ 3. Permission cleanup and management
244
+
245
+ This is designed to be called on every authz request for comprehensive user state management.
246
+
247
+ Args:
248
+ user_uid: User UID to review
249
+ updater_uid: User ID performing the review
250
+ account_for_auto_renewal: Whether to auto-renew expired cycles if auto_renew_end_datetime is valid
251
+ apply_fallback: Whether to apply fallback plans when subscriptions expire
252
+ clean_expired_permissions: Whether to clean expired permissions
253
+ review_credits: Whether to review and update subscription-based credits
254
+
255
+ Returns:
256
+ Dict containing detailed results of the review and actions taken
257
+ """
258
+ from datetime import datetime, timezone
259
+ from ipulse_shared_base_ftredge.enums import SubscriptionStatus
260
+ from ...models import UserSubscription
261
+
262
+ self.logger.info("Starting comprehensive subscription, credits, and permissions review for user %s", user_uid)
263
+
264
+ result = {
265
+ 'user_uid': user_uid,
266
+ 'timestamp': datetime.now(timezone.utc),
267
+ 'actions_taken': [],
268
+ 'subscription_status': None,
269
+ 'subscription_renewed': False,
270
+ 'fallback_applied': False,
271
+ 'subscription_revoked': False,
272
+ 'permissions_cleaned': 0,
273
+ 'permissions_added': 0,
274
+ 'credits_updated': 0,
275
+ 'error': None,
276
+ 'original_subscription': None,
277
+ 'final_subscription': None,
278
+ 'updated_userstatus': None # Will be populated with the updated UserStatus
279
+ }
280
+
281
+ try:
282
+ # Get current user status
283
+ userstatus = await self.get_userstatus(user_uid)
284
+ if not userstatus:
285
+ result['actions_taken'].append('no_userstatus_found')
286
+ return result
287
+
288
+ # Always add the current userstatus to result (will be updated if database changes occur)
289
+ result['updated_userstatus'] = userstatus
290
+
291
+ # Check if there's an active subscription
292
+ if not userstatus.active_subscription:
293
+ result['actions_taken'].append('no_active_subscription')
294
+
295
+ # Clean expired permissions if requested
296
+ if clean_expired_permissions:
297
+ expired_permissions = userstatus.cleanup_expired_permissions()
298
+ if expired_permissions > 0:
299
+ result['permissions_cleaned'] = expired_permissions
300
+ result['actions_taken'].append('cleaned_expired_permissions')
301
+
302
+ # Save changes and update the result with the updated userstatus
303
+ updated_userstatus = await self.update_userstatus(
304
+ user_uid=user_uid,
305
+ status_data=userstatus.model_dump(exclude_none=True),
306
+ updater_uid=f"review:{updater_uid}"
307
+ )
308
+ result['updated_userstatus'] = updated_userstatus
309
+
310
+ return result
311
+
312
+ # Store original subscription for comparison
313
+ result['original_subscription'] = userstatus.active_subscription
314
+ now = datetime.now(timezone.utc)
315
+
316
+ # Use the subscription's is_active() method to check current status
317
+ if userstatus.active_subscription.is_active():
318
+ result['subscription_status'] = str(SubscriptionStatus.ACTIVE)
319
+ result['final_subscription'] = userstatus.active_subscription
320
+ result['actions_taken'].append('subscription_still_active')
321
+
322
+ # Update credits if subscription is active and review_credits is enabled
323
+ if review_credits:
324
+ credits_updated = userstatus.update_subscription_credits()
325
+ if credits_updated > 0:
326
+ result['credits_updated'] = credits_updated
327
+ result['actions_taken'].append('updated_subscription_credits')
328
+
329
+ # Clean expired permissions if requested
330
+ if clean_expired_permissions:
331
+ expired_permissions = userstatus.cleanup_expired_permissions()
332
+ if expired_permissions > 0:
333
+ result['permissions_cleaned'] = expired_permissions
334
+ result['actions_taken'].append('cleaned_expired_permissions_only')
335
+
336
+ # Save changes if any updates were made
337
+ if result['credits_updated'] > 0 or result['permissions_cleaned'] > 0:
338
+ updated_userstatus = await self.update_userstatus(
339
+ user_uid=user_uid,
340
+ status_data=userstatus.model_dump(exclude_none=True),
341
+ updater_uid=f"review:{updater_uid}"
342
+ )
343
+ result['updated_userstatus'] = updated_userstatus
344
+
345
+ return result
346
+
347
+ # Subscription is not active - determine why and what to do
348
+ subscription = userstatus.active_subscription
349
+
350
+ # Check if cycle is expired but auto-renewal is still valid
351
+ if (review_auto_renewal and
352
+ subscription.auto_renew_end_datetime and
353
+ now <= subscription.auto_renew_end_datetime and
354
+ now > subscription.cycle_end_datetime_safe):
355
+
356
+ # Attempt auto-renewal by extending the cycle
357
+ try:
358
+ # Calculate new cycle start date (where the last cycle ended)
359
+ new_cycle_start = subscription.cycle_end_datetime_safe
360
+
361
+ # Create new subscription with updated cycle start date
362
+ subscription_dict = subscription.model_dump()
363
+ subscription_dict.update({
364
+ 'cycle_start_date': new_cycle_start,
365
+ 'cycle_end_datetime': None, # Let the model auto-calculate this
366
+ 'updated_at': now,
367
+ 'updated_by': f"UserstatusOperations.auto_renew:{updater_uid}"
368
+ })
369
+
370
+ renewed_subscription = UserSubscription(**subscription_dict)
371
+
372
+ # Apply the renewed subscription
373
+ userstatus.apply_subscription(
374
+ renewed_subscription,
375
+ add_associated_permissions=True,
376
+ remove_previous_subscription_permissions=True,
377
+ granted_by=f"UserstatusOperations.review.auto_renew:{updater_uid}"
378
+ )
379
+
380
+ result['subscription_renewed'] = True
381
+ result['subscription_status'] = str(userstatus.active_subscription.status)
382
+ result['final_subscription'] = renewed_subscription
383
+ result['actions_taken'].append('auto_renewed_cycle')
384
+
385
+ except (ValueError, UserStatusError) as renewal_error:
386
+ self.logger.error("Auto-renewal failed for user %s: %s", user_uid, renewal_error)
387
+ result['error'] = f"Auto-renewal failed: {str(renewal_error)}"
388
+ result['actions_taken'].append('auto_renewal_failed')
389
+ # Continue to fallback logic
390
+
391
+ # If auto-renewal didn't happen or failed, check for fallback
392
+ if not result['subscription_renewed']:
393
+ if apply_fallback and subscription.fallback_plan_id:
394
+ try:
395
+ # We need subscription_ops to handle the fallback plan logic
396
+ if self.subscription_ops:
397
+ # Import the catalog service to get fallback plan
398
+ from ...services.catalog.catalog_subscriptionplan_service import CatalogSubscriptionPlanService
399
+
400
+ catalog_service = CatalogSubscriptionPlanService(firestore_client=self.db, logger=self.logger)
401
+ fallback_plan = await catalog_service.get_subscriptionplan(subscription.fallback_plan_id)
402
+
403
+ if fallback_plan:
404
+ # Create new subscription from fallback plan
405
+ fallback_subscription = self.subscription_ops.create_subscription_from_subscriptionplan(
406
+ plan=fallback_plan,
407
+ source=f"fallback_from_{subscription.plan_id}:review:{updater_uid}",
408
+ granted_at=now,
409
+ auto_renewal_end=fallback_plan.plan_default_auto_renewal_end
410
+ )
411
+
412
+ # Apply fallback subscription
413
+ permissions_added = userstatus.apply_subscription(
414
+ fallback_subscription,
415
+ add_associated_permissions=True,
416
+ remove_previous_subscription_permissions=True,
417
+ granted_by=f"UserstatusOperations.review.fallback:{updater_uid}"
418
+ )
419
+
420
+ result['fallback_applied'] = True
421
+ result['subscription_status'] = str(userstatus.active_subscription.status)
422
+ result['final_subscription'] = fallback_subscription
423
+ result['permissions_added'] = permissions_added
424
+ result['actions_taken'].append('applied_fallback_plan')
425
+
426
+ else:
427
+ self.logger.warning("Fallback plan %s not found for user %s", subscription.fallback_plan_id, user_uid)
428
+ result['actions_taken'].append('fallback_plan_not_found')
429
+ else:
430
+ self.logger.warning("Cannot apply fallback - subscription_ops not available")
431
+ result['actions_taken'].append('fallback_unavailable_no_subscription_ops')
432
+
433
+ except (ValueError, UserStatusError) as fallback_error:
434
+ self.logger.error("Fallback application failed for user %s: %s", user_uid, fallback_error)
435
+ result['error'] = f"Fallback failed: {str(fallback_error)}"
436
+ result['actions_taken'].append('fallback_failed')
437
+ # Continue to revocation logic
438
+
439
+ # If no renewal or fallback happened, revoke the subscription
440
+ if not result['subscription_renewed'] and not result['fallback_applied']:
441
+ permissions_cleaned = userstatus.revoke_subscription(remove_associated_permissions=True)
442
+ result['subscription_revoked'] = True
443
+ result['subscription_status'] = None
444
+ result['permissions_cleaned'] = permissions_cleaned
445
+ result['actions_taken'].append('subscription_revoked')
446
+
447
+ # Clean up all expired permissions (not just those associated with the subscription)
448
+ if clean_expired_permissions:
449
+ additional_expired = userstatus.cleanup_expired_permissions()
450
+ if additional_expired > 0:
451
+ result['permissions_cleaned'] += additional_expired
452
+ result['actions_taken'].append('cleaned_additional_expired_permissions')
453
+
454
+ # Save all changes to database
455
+ updated_userstatus = await self.update_userstatus(
456
+ user_uid=user_uid,
457
+ status_data=userstatus.model_dump(exclude_none=False), # Include None values for proper updates
458
+ updater_uid=f"review:{updater_uid}"
459
+ )
460
+
461
+ # Add the updated UserStatus to the result
462
+ result['updated_userstatus'] = updated_userstatus
463
+
464
+ self.logger.info(
465
+ "Completed comprehensive review for user %s. Status: %s, Actions: %s",
466
+ user_uid, result['subscription_status'], result['actions_taken']
467
+ )
468
+
469
+ except Exception as e:
470
+ self.logger.error("Comprehensive review failed for user %s: %s", user_uid, e, exc_info=True)
471
+ result['error'] = str(e)
472
+ result['actions_taken'].append('review_failed')
473
+ # Re-raise for proper error handling
474
+ raise
475
+
476
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 22.1.1
3
+ Version: 23.1.1
4
4
  Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
5
5
  Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
6
6
  Author: Russlan Ramdowar
@@ -2,50 +2,49 @@ ipulse_shared_core_ftredge/__init__.py,sha256=-KbdF_YW8pgf7pVv9qh_cA1xrNm_B9zigH
2
2
  ipulse_shared_core_ftredge/cache/__init__.py,sha256=i2fPojmZiBwAoY5ovnnnME9USl4bi8MRPYkAgEfACfI,136
3
3
  ipulse_shared_core_ftredge/cache/shared_cache.py,sha256=BDJtkTsdfmVjKaUkbBXOhJ2Oib7Li0UCsPjWX7FLIPU,12940
4
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
5
+ ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py,sha256=iwNqOEFHEF0qK7vfRPRXpAexTwF5UOLsfdir1wEo9_E,3646
6
6
  ipulse_shared_core_ftredge/dependencies/auth_protected_router.py,sha256=em5D5tE7OkgZmuCtYCKuUAnIZCgRJhCF8Ye5QmtGWlk,1807
7
- ipulse_shared_core_ftredge/dependencies/authz_for_apis.py,sha256=TnJ2ubGUZRxRa6v-OLC2uCLzaoCuX1GkXSaFJMaYg0s,15793
7
+ ipulse_shared_core_ftredge/dependencies/authz_for_apis.py,sha256=t2hz1wAVxCT0lCDVf6gmcYeLuUCR7mIXYsThKg0cIlM,14992
8
8
  ipulse_shared_core_ftredge/dependencies/firestore_client.py,sha256=VbTb121nsc9EZPd1RDEsHBLW5pIiVw6Wdo2JFL4afMg,714
9
9
  ipulse_shared_core_ftredge/exceptions/__init__.py,sha256=Cb_RsIie4DbT_NLwFVwjw4riDKsNNRQEuAvHvYa-Zco,1038
10
- ipulse_shared_core_ftredge/exceptions/base_exceptions.py,sha256=RuihEpgXdUIR2XEXaP6aJnepePbvZ2RZYQwcKfatGPw,4981
10
+ ipulse_shared_core_ftredge/exceptions/base_exceptions.py,sha256=117YsiCbYLLBu_D0IffYFVSX2yh-pisALMtoSMwj6xI,5338
11
11
  ipulse_shared_core_ftredge/exceptions/user_exceptions.py,sha256=I-nm21MKrUYEoybpRODeYNzc184HfgHvRZQm_xux4VY,6824
12
12
  ipulse_shared_core_ftredge/models/__init__.py,sha256=oaBL_BZWd7hIDu2K7yxtVKxtkOD9UF9r9_V2ZIPQ8Yk,350
13
13
  ipulse_shared_core_ftredge/models/base_api_response.py,sha256=OwuWI2PsMSLDkFt643u35ZhW5AHFEMMAGnGprmUO0fA,2380
14
14
  ipulse_shared_core_ftredge/models/base_data_model.py,sha256=GZ7KTT5FanHTgvmaHHTxawzAJtuixkbyb-SuL-mjWys,2193
15
15
  ipulse_shared_core_ftredge/models/catalog/__init__.py,sha256=9oKJ74_mTtmj-0iDnRBiPI8m8QJ2J9wvx4ZWaZw3zRk,208
16
- ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py,sha256=5q1yUwy_755UNt7FZ4Ez-1njF0APSyzmiLbhGP1f2g0,9069
17
- ipulse_shared_core_ftredge/models/catalog/usertype.py,sha256=W42bis9l6_FL5Q3HY8pqxs1b0gkcIGgGYpLTOU6fYxE,6319
16
+ ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py,sha256=WxKWzTmHJlvFQj6Kq69iWMoFkx_veiPhonFo8dUGzZw,9148
17
+ ipulse_shared_core_ftredge/models/catalog/usertype.py,sha256=E_qQCq7ytiFca6umaX_-_a6TuDh83YwSKtFKdeU4ErM,6584
18
18
  ipulse_shared_core_ftredge/models/user/__init__.py,sha256=TheOLldY6v-OK9i-A5mQNIxjHhBFpuOJ43mi-swcN_o,196
19
19
  ipulse_shared_core_ftredge/models/user/user_permissions.py,sha256=CUWDBPLPmKN3o43BTZAt0zJvm_ekjJA46iV6rVNp-oc,2411
20
- ipulse_shared_core_ftredge/models/user/user_subscription.py,sha256=f0EFPtIQU_KKB3LO1MKZYraaxSdJp-FqeZDPKs2VP6E,8587
20
+ ipulse_shared_core_ftredge/models/user/user_subscription.py,sha256=83ncQUHUYF6S19KdZM7-nLEVjD4VPIO88ZRVkXeNnE8,13514
21
21
  ipulse_shared_core_ftredge/models/user/userauth.py,sha256=PbS-XSLxDl1feskI0iCziGvmMiLuF8o_ZTspAx1B0j0,3679
22
22
  ipulse_shared_core_ftredge/models/user/userprofile.py,sha256=7VbE4qiKpDxZsNTk-IJKA32QxW0JOo8KWPkj8h9J2-Y,6945
23
- ipulse_shared_core_ftredge/models/user/userstatus.py,sha256=NpSQWlbCnFRQ_Gnx7WLkyt3dKgRDf4-MRrJU5VYF7DA,16748
23
+ ipulse_shared_core_ftredge/models/user/userstatus.py,sha256=9BGaKiKL3JeSNQ8ZRRc0taLgSu0uxtBu5NRVsCbVXW4,18776
24
24
  ipulse_shared_core_ftredge/monitoring/__init__.py,sha256=gUoJjT0wj-cQYnMWheWbh1mmRHmaeojmnBZTj7KPNus,61
25
25
  ipulse_shared_core_ftredge/monitoring/tracemon.py,sha256=Trku0qrwWvEcvKsBWiYokd_G3fcH-5uP2wRVgcgIz_k,11596
26
26
  ipulse_shared_core_ftredge/services/__init__.py,sha256=9AkMLCHNswhuNbQuJZaEVz4zt4F84PxfJLyU_bYk4Js,565
27
27
  ipulse_shared_core_ftredge/services/charging_processors.py,sha256=9Re24dyXdjKYbqwx6uNLu3JBzIaw87TAV7Oe__M1QnA,16308
28
28
  ipulse_shared_core_ftredge/services/user_charging_service.py,sha256=C3wMfgBXOz4RM1RLc7up2_pIPAnZv8ZYu-lLrkofTmc,14625
29
29
  ipulse_shared_core_ftredge/services/base/__init__.py,sha256=zhyrHQMM0cLJr4spk2b6VsgJXuWBy7hUBzhrq_Seg9k,389
30
- ipulse_shared_core_ftredge/services/base/base_firestore_service.py,sha256=xXmPfDEgBa4trWMJz1UBJRDLPxi8TtG2jDFbo_B28pw,19313
30
+ ipulse_shared_core_ftredge/services/base/base_firestore_service.py,sha256=leZFwxb1ruheypqudpKnuNtRQXtO4KNeoJk6ZACozHc,19512
31
31
  ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py,sha256=ya5Asff9BQodYnJVAw6M_Pm8WtVRPpEK7izFlZ2MyjA,10016
32
32
  ipulse_shared_core_ftredge/services/catalog/__init__.py,sha256=ctc2nDGwsW_Ji4lk9pys3oyNwR_V-gHSbSHawym5fKQ,385
33
- ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py,sha256=mbwCC1RnIZEav5i5sRGT15nxQJF0qMVA2LT8BAjmJuY,9264
34
- ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py,sha256=pZdsRt9V96NcYTRremTf76fDL126lAiraxGs936i0aU,9959
33
+ ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py,sha256=X5xAi9sOk_F1ky0ECwPVlwIPPsN2PrZC6bN_pASGDjQ,9702
34
+ ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py,sha256=C_VWxZ5iPcybjsSXdmZHyqS--rI3KY8pp7JDIy_L7S8,12833
35
35
  ipulse_shared_core_ftredge/services/user/__init__.py,sha256=jmkD5XzAmaD8QV2UsgB5xynGcfsXliWtRtN2pt6kzbA,884
36
- ipulse_shared_core_ftredge/services/user/firebase_auth_admin_helpers.py,sha256=7N-MWpCwzWCjIuIFXGv1sIjJJcU9M92nWOfRyMEuHbE,5430
37
- ipulse_shared_core_ftredge/services/user/user_core_service.py,sha256=9nhFgFVPp188JMiZYINLwyHGtUYqtbHZhIR6cQMhj00,23648
38
- ipulse_shared_core_ftredge/services/user/user_multistep_operations.py,sha256=hQ1-BygC2Cxin6AUsEVgEWfZg035v5yn__sAoPzy0Us,35543
36
+ ipulse_shared_core_ftredge/services/user/user_core_service.py,sha256=o0trN4yTbyh-BJbXnin9XmS8hW5jOQW6RdegdQ2sRNo,28269
37
+ ipulse_shared_core_ftredge/services/user/user_multistep_operations.py,sha256=0MfMaKLGpVsgfD-Vgaa4s2dKk9nNoH6snWx_skkPy_o,39705
39
38
  ipulse_shared_core_ftredge/services/user/user_permissions_operations.py,sha256=FByszIWo-qooLVXFTw0tGLWksIJEqHUPc_ZGwue0_pM,15753
40
- ipulse_shared_core_ftredge/services/user/user_subscription_operations.py,sha256=h5jz4jvnwocDIwHa5VUX3_u4Qzrkt5A1s06aL5Bafm0,21266
39
+ ipulse_shared_core_ftredge/services/user/user_subscription_operations.py,sha256=z98EO67wHlnDj1V7JK14yq6yaIoTVcX5X5v4-taZFHw,21651
41
40
  ipulse_shared_core_ftredge/services/user/userauth_operations.py,sha256=9l2uBAcAxbUnilK8MZ7IlHzaGiaPuqx7nIC51mAyR9w,36120
42
41
  ipulse_shared_core_ftredge/services/user/userprofile_operations.py,sha256=_qyIEAQYCTV-subgP-5naMs_26apCpauomE6qmCCVWs,7333
43
- ipulse_shared_core_ftredge/services/user/userstatus_operations.py,sha256=Gz2P4toJNs3ZMpGBvmN0HfiFqonRv6G3jTKkDz7mjuA,8927
42
+ ipulse_shared_core_ftredge/services/user/userstatus_operations.py,sha256=sW4Q-aMG1mjKvqVKK5AA93-G57FPBCkxO7rPfCkhBd8,22726
44
43
  ipulse_shared_core_ftredge/utils/__init__.py,sha256=JnxUb8I2MRjJC7rBPXSrpwBIQDEOku5O9JsiTi3oun8,56
45
44
  ipulse_shared_core_ftredge/utils/custom_json_encoder.py,sha256=DblQLD0KOSNDyQ58wQRogBrShIXzPIZUw_oGOBATnJY,1366
46
45
  ipulse_shared_core_ftredge/utils/json_encoder.py,sha256=QkcaFneVv3-q-s__Dz4OiUWYnM6jgHDJrDMdPv09RCA,2093
47
- ipulse_shared_core_ftredge-22.1.1.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
48
- ipulse_shared_core_ftredge-22.1.1.dist-info/METADATA,sha256=Q-CLpF1xpkRoIMZ5ab17rGskMnkPdA6M04e0qj8yqHI,782
49
- ipulse_shared_core_ftredge-22.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
50
- ipulse_shared_core_ftredge-22.1.1.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
51
- ipulse_shared_core_ftredge-22.1.1.dist-info/RECORD,,
46
+ ipulse_shared_core_ftredge-23.1.1.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
47
+ ipulse_shared_core_ftredge-23.1.1.dist-info/METADATA,sha256=keIkjScj_B7Wix1MqoCIY8aR5JRAVkbdJwFd3HWnslg,782
48
+ ipulse_shared_core_ftredge-23.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
+ ipulse_shared_core_ftredge-23.1.1.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
50
+ ipulse_shared_core_ftredge-23.1.1.dist-info/RECORD,,