ipulse-shared-core-ftredge 26.1.1__tar.gz → 27.2.0__tar.gz
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-26.1.1/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-27.2.0}/PKG-INFO +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/setup.py +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +27 -20
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/usertype.py +2 -2
- ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py +43 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/user_subscription.py +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userprofile.py +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userstatus.py +2 -2
- ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +2 -2
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +2 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +1 -1
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/LICENCE +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/README.md +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/pyproject.toml +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/setup.cfg +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/cache/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/cache/shared_cache.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/auth_protected_router.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/authz_credit_extraction.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/firestore_client.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/base_exceptions.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/user_exceptions.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/base_api_response.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/credit_api_response.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/custom_json_response.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/user_permissions.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userauth.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/monitoring/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/monitoring/tracemon.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/charging_processors.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_charging_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_core_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userauth_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user_charging_service.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
- {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/tests/test_shared_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version:
|
|
3
|
+
Version: 27.2.0
|
|
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
|
|
@@ -12,7 +12,7 @@ License-File: LICENCE
|
|
|
12
12
|
Requires-Dist: pydantic[email]~=2.5
|
|
13
13
|
Requires-Dist: python-dateutil~=2.8
|
|
14
14
|
Requires-Dist: fastapi~=0.115.8
|
|
15
|
-
Requires-Dist: ipulse_shared_base_ftredge
|
|
15
|
+
Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
|
|
16
16
|
Dynamic: author
|
|
17
17
|
Dynamic: classifier
|
|
18
18
|
Dynamic: home-page
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
5
|
name='ipulse_shared_core_ftredge',
|
|
6
|
-
version='
|
|
6
|
+
version='27.2.0',
|
|
7
7
|
package_dir={'': 'src'}, # Specify the source directory
|
|
8
8
|
packages=find_packages(where='src'), # Look for packages in 'src'
|
|
9
9
|
install_requires=[
|
|
@@ -11,7 +11,7 @@ setup(
|
|
|
11
11
|
'pydantic[email]~=2.5',
|
|
12
12
|
'python-dateutil~=2.8',
|
|
13
13
|
'fastapi~=0.115.8',
|
|
14
|
-
'ipulse_shared_base_ftredge
|
|
14
|
+
'ipulse_shared_base_ftredge~=12.2.0',
|
|
15
15
|
],
|
|
16
16
|
author='Russlan Ramdowar',
|
|
17
17
|
description='Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.',
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import logging
|
|
3
|
-
import asyncio
|
|
4
3
|
from typing import Optional, Iterable, Dict, Any, List
|
|
5
4
|
from datetime import datetime, timedelta, timezone
|
|
6
5
|
import httpx
|
|
7
6
|
from fastapi import HTTPException, Request
|
|
7
|
+
from ipulse_shared_base_ftredge import ApprovalStatus
|
|
8
8
|
from ipulse_shared_core_ftredge.exceptions import ServiceError, ResourceNotFoundError
|
|
9
9
|
from ipulse_shared_core_ftredge.models import UserStatus
|
|
10
10
|
from ipulse_shared_core_ftredge.services import UserCoreService
|
|
11
|
-
from ipulse_shared_base_ftredge import ApprovalStatus
|
|
12
11
|
|
|
13
12
|
# Cache TTL constant
|
|
14
13
|
USERSTATUS_CACHE_TTL = 60 # 60 seconds
|
|
@@ -63,12 +62,13 @@ class UserStatusCache:
|
|
|
63
62
|
userstatus_cache = UserStatusCache()
|
|
64
63
|
|
|
65
64
|
# Replace the logger dependency with a standard logger
|
|
66
|
-
|
|
65
|
+
_module_logger = logging.getLogger(__name__)
|
|
67
66
|
|
|
68
67
|
async def get_userstatus(
|
|
69
68
|
user_uid: str,
|
|
70
69
|
user_core_service: UserCoreService,
|
|
71
|
-
force_fresh: bool = False
|
|
70
|
+
force_fresh: bool = False,
|
|
71
|
+
logger: Optional[logging.Logger] = None
|
|
72
72
|
) -> tuple[UserStatus, bool]:
|
|
73
73
|
"""
|
|
74
74
|
Lightweight fetch of user status with caching.
|
|
@@ -78,10 +78,12 @@ async def get_userstatus(
|
|
|
78
78
|
user_uid: User ID to fetch status for
|
|
79
79
|
user_core_service: UserCoreService for data retrieval
|
|
80
80
|
force_fresh: Whether to bypass cache
|
|
81
|
+
logger: Optional logger instance to use.
|
|
81
82
|
|
|
82
83
|
Returns:
|
|
83
84
|
Tuple of (UserStatus object, whether cache was used)
|
|
84
85
|
"""
|
|
86
|
+
log = logger if logger else _module_logger
|
|
85
87
|
cache_used = False
|
|
86
88
|
|
|
87
89
|
# Check cache first unless forced fresh
|
|
@@ -109,7 +111,7 @@ async def get_userstatus(
|
|
|
109
111
|
raise ValueError(f"Expected UserStatus object or dict, got {type(status_obj)}")
|
|
110
112
|
|
|
111
113
|
except Exception as e:
|
|
112
|
-
|
|
114
|
+
log.error(f"Error fetching user status via UserCoreService: {str(e)}")
|
|
113
115
|
raise ServiceError(
|
|
114
116
|
operation="fetching user status for authz via UserCoreService",
|
|
115
117
|
error=e,
|
|
@@ -134,11 +136,12 @@ def _validate_resource_fields(fields: Dict[str, Any]) -> List[str]:
|
|
|
134
136
|
}
|
|
135
137
|
return list(valid_fields.keys())
|
|
136
138
|
|
|
137
|
-
async def extract_request_fields(request: Request) -> Optional[List[str]]:
|
|
139
|
+
async def extract_request_fields(request: Request, logger: Optional[logging.Logger] = None) -> Optional[List[str]]:
|
|
138
140
|
"""
|
|
139
141
|
Extract fields from request body for both PATCH and POST methods.
|
|
140
142
|
For GET and DELETE methods, return None as they typically don't have a body.
|
|
141
143
|
"""
|
|
144
|
+
log = logger if logger else _module_logger
|
|
142
145
|
# Skip body extraction for GET and DELETE requests
|
|
143
146
|
if request.method.upper() in ["GET", "DELETE", "HEAD", "OPTIONS"]:
|
|
144
147
|
return None
|
|
@@ -161,7 +164,7 @@ async def extract_request_fields(request: Request) -> Optional[List[str]]:
|
|
|
161
164
|
return None
|
|
162
165
|
|
|
163
166
|
except Exception as e:
|
|
164
|
-
|
|
167
|
+
log.warning(f"Could not extract fields from request body: {str(e)}")
|
|
165
168
|
return None # Return None instead of raising an error
|
|
166
169
|
|
|
167
170
|
# Main authorization function with configurable timeout
|
|
@@ -169,6 +172,7 @@ async def authorizeAPIRequest(
|
|
|
169
172
|
request: Request,
|
|
170
173
|
user_core_service: UserCoreService, # UserCoreService instance for better integration
|
|
171
174
|
request_resource_fields: Optional[Iterable[str]] = None,
|
|
175
|
+
logger: Optional[logging.Logger] = None
|
|
172
176
|
|
|
173
177
|
) -> Dict[str, Any]:
|
|
174
178
|
"""
|
|
@@ -179,6 +183,7 @@ async def authorizeAPIRequest(
|
|
|
179
183
|
request: The incoming request
|
|
180
184
|
user_core_service: UserCoreService instance for better integration
|
|
181
185
|
request_resource_fields: Fields being accessed/modified in the request
|
|
186
|
+
logger: Optional logger instance to use.
|
|
182
187
|
|
|
183
188
|
Returns:
|
|
184
189
|
Authorization result containing decision details
|
|
@@ -186,18 +191,19 @@ async def authorizeAPIRequest(
|
|
|
186
191
|
Raises:
|
|
187
192
|
HTTPException: For authorization failures (403) or service errors (500)
|
|
188
193
|
"""
|
|
194
|
+
log = logger if logger else _module_logger
|
|
189
195
|
opa_decision = None
|
|
190
196
|
try:
|
|
191
197
|
# Extract fields for both PATCH and POST if not provided
|
|
192
198
|
if not request_resource_fields:
|
|
193
|
-
request_resource_fields = await extract_request_fields(request)
|
|
199
|
+
request_resource_fields = await extract_request_fields(request, logger=log)
|
|
194
200
|
|
|
195
201
|
# Extract request context and Firebase user claims
|
|
196
202
|
firebase_user = request.state.user
|
|
197
|
-
|
|
203
|
+
log.debug(f"Firebase user: {firebase_user}")
|
|
198
204
|
user_uid = firebase_user.get('uid')
|
|
199
205
|
if not user_uid:
|
|
200
|
-
|
|
206
|
+
log.debug(f"Authorization denied for {request.method} {request.url.path}: No user UID found")
|
|
201
207
|
raise HTTPException(
|
|
202
208
|
status_code=403,
|
|
203
209
|
detail="Not authorized to access this resource"
|
|
@@ -214,10 +220,11 @@ async def authorizeAPIRequest(
|
|
|
214
220
|
user_uid=user_uid,
|
|
215
221
|
user_core_service=user_core_service,
|
|
216
222
|
force_fresh=force_fresh,
|
|
223
|
+
logger=log
|
|
217
224
|
)
|
|
218
225
|
|
|
219
226
|
# Perform comprehensive review and cleanup synchronously to ensure accurate auth data
|
|
220
|
-
|
|
227
|
+
log.debug(f"Comprehensive review for userstatus : {user_status_obj} during authz")
|
|
221
228
|
if user_core_service:
|
|
222
229
|
try:
|
|
223
230
|
review_result = await user_core_service.review_and_clean_active_subscription_credits_and_permissions(
|
|
@@ -228,10 +235,10 @@ async def authorizeAPIRequest(
|
|
|
228
235
|
clean_expired_permissions=True,
|
|
229
236
|
review_credits=True
|
|
230
237
|
)
|
|
231
|
-
|
|
238
|
+
log.debug(f"Review result for userstatus : {review_result} during authz")
|
|
232
239
|
# Refresh user status after comprehensive review if any actions were taken
|
|
233
240
|
if review_result.get('actions_taken'):
|
|
234
|
-
|
|
241
|
+
log.info(f"Authz middleware performed comprehensive review for user {user_uid}: {review_result['actions_taken']}")
|
|
235
242
|
# Use the updated UserStatus returned from the review function
|
|
236
243
|
if 'updated_userstatus' in review_result:
|
|
237
244
|
user_status_obj = review_result['updated_userstatus']
|
|
@@ -241,7 +248,7 @@ async def authorizeAPIRequest(
|
|
|
241
248
|
userstatus_cache.set(user_uid, user_status_obj)
|
|
242
249
|
|
|
243
250
|
except Exception as e:
|
|
244
|
-
|
|
251
|
+
log.warning(f"Comprehensive review failed for user {user_uid} during auth: {str(e)}")
|
|
245
252
|
# Continue with existing status if review fails
|
|
246
253
|
|
|
247
254
|
# Get valid permissions after comprehensive review
|
|
@@ -299,17 +306,17 @@ async def authorizeAPIRequest(
|
|
|
299
306
|
)
|
|
300
307
|
|
|
301
308
|
if response.status_code != 200:
|
|
302
|
-
|
|
309
|
+
log.error(f"OPA authorization failed: {response.text}")
|
|
303
310
|
raise HTTPException(
|
|
304
311
|
status_code=500,
|
|
305
312
|
detail="Authorization service error"
|
|
306
313
|
)
|
|
307
314
|
|
|
308
315
|
result = response.json()
|
|
309
|
-
|
|
316
|
+
log.debug(f"OPA response: {result}")
|
|
310
317
|
# Handle OPA response format
|
|
311
318
|
if "result" not in result:
|
|
312
|
-
|
|
319
|
+
log.warning("OPA response missing 'result' field")
|
|
313
320
|
raise HTTPException(
|
|
314
321
|
status_code=500,
|
|
315
322
|
detail="Authorization service error: OPA response format unexpected"
|
|
@@ -320,14 +327,14 @@ async def authorizeAPIRequest(
|
|
|
320
327
|
|
|
321
328
|
# Handle authorization denial
|
|
322
329
|
if not allow:
|
|
323
|
-
|
|
330
|
+
log.debug(f"Authorization denied for {request.method} {request.url.path}")
|
|
324
331
|
raise HTTPException(
|
|
325
332
|
status_code=403,
|
|
326
333
|
detail=f"Not authorized to {request.method} {request.url.path}"
|
|
327
334
|
)
|
|
328
335
|
|
|
329
336
|
except httpx.RequestError as e:
|
|
330
|
-
|
|
337
|
+
log.error(f"Failed to connect to OPA: {str(e)}")
|
|
331
338
|
raise HTTPException(
|
|
332
339
|
status_code=500,
|
|
333
340
|
detail="Authorization service temporarily unavailable"
|
|
@@ -346,7 +353,7 @@ async def authorizeAPIRequest(
|
|
|
346
353
|
raise
|
|
347
354
|
except Exception as e:
|
|
348
355
|
# Only log unexpected errors at ERROR level
|
|
349
|
-
|
|
356
|
+
log.error(f"Unexpected error during authorization for {request.method} {request.url.path}: {str(e)}")
|
|
350
357
|
raise HTTPException(
|
|
351
358
|
status_code=500,
|
|
352
359
|
detail="Internal authorization error"
|
|
@@ -10,7 +10,7 @@ from enum import StrEnum
|
|
|
10
10
|
from datetime import datetime, timezone, timedelta
|
|
11
11
|
from pydantic import Field, ConfigDict, field_validator,model_validator, BaseModel
|
|
12
12
|
from ipulse_shared_base_ftredge import (Layer, Module, list_enums_as_lower_strings,
|
|
13
|
-
|
|
13
|
+
SystemSubject, SubscriptionPlanName,ObjectOverallStatus,
|
|
14
14
|
SubscriptionStatus, TimeUnit)
|
|
15
15
|
from ..base_data_model import BaseDataModel
|
|
16
16
|
from ..user.user_permissions import UserPermission
|
|
@@ -60,7 +60,7 @@ class SubscriptionPlan(BaseDataModel):
|
|
|
60
60
|
model_config = ConfigDict(extra="forbid")
|
|
61
61
|
|
|
62
62
|
VERSION: ClassVar[float] = 1.0
|
|
63
|
-
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE,
|
|
63
|
+
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.CATALOG))
|
|
64
64
|
OBJ_REF: ClassVar[str] = "subscriptionplan"
|
|
65
65
|
|
|
66
66
|
# System-managed fields
|
|
@@ -9,7 +9,7 @@ based on their user type (superadmin, admin, internal, authenticated, anonymous)
|
|
|
9
9
|
from typing import Dict, Any, Optional, ClassVar, List
|
|
10
10
|
from datetime import datetime
|
|
11
11
|
from pydantic import Field, ConfigDict, field_validator, model_validator
|
|
12
|
-
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings,
|
|
12
|
+
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, ObjectOverallStatus
|
|
13
13
|
from ipulse_shared_base_ftredge.enums.enums_iam import IAMUserType
|
|
14
14
|
from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
|
|
15
15
|
from ipulse_shared_core_ftredge.models.user.user_permissions import UserPermission
|
|
@@ -28,7 +28,7 @@ class UserType(BaseDataModel):
|
|
|
28
28
|
model_config = ConfigDict(extra="forbid")
|
|
29
29
|
|
|
30
30
|
VERSION: ClassVar[float] = 1.0
|
|
31
|
-
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name,
|
|
31
|
+
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name, SystemSubject.CATALOG.name))
|
|
32
32
|
OBJ_REF: ClassVar[str] = "usertype"
|
|
33
33
|
|
|
34
34
|
# System-managed fields
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# pylint: disable=missing-module-docstring, missing-class-docstring
|
|
2
|
+
from typing import List, Optional, TypeVar, Generic
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pydantic import Field, BaseModel
|
|
5
|
+
from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
|
|
6
|
+
from ipulse_shared_base_ftredge.enums import DatasetLineage, DatasetScope
|
|
7
|
+
|
|
8
|
+
# Generic type for the records within the dataset
|
|
9
|
+
RecordsSamplingType = TypeVar('RecordsSamplingType', bound=BaseModel)
|
|
10
|
+
|
|
11
|
+
class TimeSeriesPackagedDatasetModel(BaseDataModel, Generic[RecordsSamplingType]):
|
|
12
|
+
"""
|
|
13
|
+
An intermediary model for time series datasets that holds aggregated records.
|
|
14
|
+
It provides a generic way to handle different types of time series records.
|
|
15
|
+
"""
|
|
16
|
+
dataset_id: str = Field(..., description="The unique identifier for this dataset, often matching the asset ID.")
|
|
17
|
+
|
|
18
|
+
dataset_modality: str = Field(..., description="The modality of the dataset, e.g., 'time_series', 'cross_sectional'.")
|
|
19
|
+
dataset_lineage: DatasetLineage = Field(..., description="The lineage of the data, indicating its origin and transformations.")
|
|
20
|
+
dataset_partition: DatasetScope = Field(..., description="The partition type of the dataset, e.g., full, subsampled.")
|
|
21
|
+
|
|
22
|
+
# Generic lists for different temporal buckets of records
|
|
23
|
+
max_bulk_records: List[RecordsSamplingType] = Field(default_factory=list)
|
|
24
|
+
latest_bulk_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
|
|
25
|
+
latest_intraday_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
|
|
26
|
+
|
|
27
|
+
# Metadata fields
|
|
28
|
+
max_bulk_updated_at: Optional[datetime] = None
|
|
29
|
+
max_bulk_updated_by: Optional[str] = None
|
|
30
|
+
max_bulk_recent_date_id: Optional[datetime] = None
|
|
31
|
+
max_bulk_oldest_date_id: Optional[datetime] = None
|
|
32
|
+
latest_bulk_recent_date_id: Optional[datetime] = None
|
|
33
|
+
latest_bulk_oldest_date_id: Optional[datetime] = None
|
|
34
|
+
latest_record_updated_at: Optional[datetime] = None
|
|
35
|
+
latest_record_updated_by: Optional[str] = None
|
|
36
|
+
latest_record_change_id: Optional[str] = None
|
|
37
|
+
latest_intraday_bulk_updated_at: Optional[datetime] = None
|
|
38
|
+
latest_intraday_bulk_updated_by: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def id(self) -> str:
|
|
42
|
+
"""Return dataset_id for backward compatibility and consistency."""
|
|
43
|
+
return self.dataset_id
|
|
@@ -3,7 +3,7 @@ from dateutil.relativedelta import relativedelta
|
|
|
3
3
|
import uuid
|
|
4
4
|
from typing import Optional, ClassVar, Dict, Any, List
|
|
5
5
|
from pydantic import Field, ConfigDict, model_validator
|
|
6
|
-
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings,
|
|
6
|
+
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, SubscriptionPlanName, SubscriptionStatus, TimeUnit
|
|
7
7
|
from ..base_data_model import BaseDataModel
|
|
8
8
|
from .user_permissions import UserPermission
|
|
9
9
|
# ORIGINAL AUTHOR ="russlan.ramdowar;russlan@ftredge.com"
|
|
@@ -22,7 +22,7 @@ class UserSubscription(BaseDataModel):
|
|
|
22
22
|
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
23
23
|
|
|
24
24
|
VERSION: ClassVar[float] = 3.0 # Incremented version for direct fields instead of computed
|
|
25
|
-
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE,
|
|
25
|
+
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.SUBSCRIPTION))
|
|
26
26
|
OBJ_REF: ClassVar[str] = "subscription"
|
|
27
27
|
|
|
28
28
|
# System-managed fields (read-only)
|
|
@@ -3,7 +3,7 @@ from datetime import date, datetime
|
|
|
3
3
|
import re # Add re import
|
|
4
4
|
from typing import Set, Optional, ClassVar, Dict, Any, List
|
|
5
5
|
from pydantic import EmailStr, Field, ConfigDict, model_validator, field_validator
|
|
6
|
-
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings,
|
|
6
|
+
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, IAMUserType
|
|
7
7
|
from ..base_data_model import BaseDataModel
|
|
8
8
|
# ORIGINAL AUTHOR ="Russlan Ramdowar;russlan@ftredge.com"
|
|
9
9
|
# CLASS_ORGIN_DATE=datetime(2024, 2, 12, 20, 5)
|
|
@@ -17,7 +17,7 @@ class UserProfile(BaseDataModel):
|
|
|
17
17
|
|
|
18
18
|
# Class constants
|
|
19
19
|
VERSION: ClassVar[float] = 5.0 # Incremented version for primary_usertype addition
|
|
20
|
-
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE,
|
|
20
|
+
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
|
|
21
21
|
OBJ_REF: ClassVar[str] = "userprofile"
|
|
22
22
|
|
|
23
23
|
schema_version: float = Field(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
from datetime import datetime, timezone, timedelta
|
|
3
3
|
from typing import Set, Optional, Dict, List, ClassVar, Any
|
|
4
4
|
from pydantic import Field, ConfigDict, model_validator, field_validator
|
|
5
|
-
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings,
|
|
5
|
+
from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, TimeUnit
|
|
6
6
|
from ipulse_shared_base_ftredge.enums.enums_iam import IAMUnit
|
|
7
7
|
from .user_subscription import UserSubscription
|
|
8
8
|
from ..base_data_model import BaseDataModel
|
|
@@ -20,7 +20,7 @@ class UserStatus(BaseDataModel):
|
|
|
20
20
|
|
|
21
21
|
# Class constants
|
|
22
22
|
VERSION: ClassVar[float] = 7.0 # Major version bump for flattened IAM permissions structure
|
|
23
|
-
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE,
|
|
23
|
+
DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
|
|
24
24
|
OBJ_REF: ClassVar[str] = "userstatus"
|
|
25
25
|
|
|
26
26
|
# Centralized collection name and document ID prefix
|
ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
ADDED
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version:
|
|
3
|
+
Version: 27.2.0
|
|
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
|
|
@@ -12,7 +12,7 @@ License-File: LICENCE
|
|
|
12
12
|
Requires-Dist: pydantic[email]~=2.5
|
|
13
13
|
Requires-Dist: python-dateutil~=2.8
|
|
14
14
|
Requires-Dist: fastapi~=0.115.8
|
|
15
|
-
Requires-Dist: ipulse_shared_base_ftredge
|
|
15
|
+
Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
|
|
16
16
|
Dynamic: author
|
|
17
17
|
Dynamic: classifier
|
|
18
18
|
Dynamic: home-page
|
|
@@ -24,6 +24,7 @@ src/ipulse_shared_core_ftredge/models/base_api_response.py
|
|
|
24
24
|
src/ipulse_shared_core_ftredge/models/base_data_model.py
|
|
25
25
|
src/ipulse_shared_core_ftredge/models/credit_api_response.py
|
|
26
26
|
src/ipulse_shared_core_ftredge/models/custom_json_response.py
|
|
27
|
+
src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py
|
|
27
28
|
src/ipulse_shared_core_ftredge/models/catalog/__init__.py
|
|
28
29
|
src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py
|
|
29
30
|
src/ipulse_shared_core_ftredge/models/catalog/usertype.py
|
|
@@ -54,6 +55,7 @@ src/ipulse_shared_core_ftredge/services/user/userauth_operations.py
|
|
|
54
55
|
src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py
|
|
55
56
|
src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py
|
|
56
57
|
src/ipulse_shared_core_ftredge/utils/__init__.py
|
|
58
|
+
src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
|
|
57
59
|
src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py
|
|
58
60
|
src/ipulse_shared_core_ftredge/utils/json_encoder.py
|
|
59
61
|
tests/test_shared_cache.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/tests/test_shared_cache.py
RENAMED
|
File without changes
|