ipulse-shared-core-ftredge 3.2.3__tar.gz → 4.1.1__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-3.2.3/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-4.1.1}/PKG-INFO +1 -1
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/setup.py +1 -1
- ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/__init__.py +9 -0
- ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/exceptions.py +71 -0
- ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/models/api_response.py +22 -0
- ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/services/__init__.py +1 -0
- ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/services/base_service.py +75 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +1 -1
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +4 -0
- ipulse_shared_core_ftredge-3.2.3/src/ipulse_shared_core_ftredge/__init__.py +0 -4
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/LICENCE +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/README.md +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/pyproject.toml +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/setup.cfg +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/organisation.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/resource_catalog_item.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_auth.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_profile.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_profile_update.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_status.py +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
- {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/tests/test_utils_gcp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.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
|
|
@@ -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='4.1.1',
|
|
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=[
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# pylint: disable=missing-module-docstring
|
|
2
|
+
from .models import ( UserAuth, UserProfile,
|
|
3
|
+
UserStatus, UserProfileUpdate,
|
|
4
|
+
Organisation)
|
|
5
|
+
|
|
6
|
+
from .exceptions import (BaseServiceException, ResourceNotFoundError, AuthorizationError,
|
|
7
|
+
ValidationError )
|
|
8
|
+
|
|
9
|
+
from .services import (BaseFirestoreService)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from fastapi import HTTPException
|
|
2
|
+
from typing import Optional, Any, Dict
|
|
3
|
+
|
|
4
|
+
class BaseServiceException(HTTPException):
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
status_code: int,
|
|
8
|
+
detail: str,
|
|
9
|
+
resource_type: str,
|
|
10
|
+
resource_id: Optional[str] = None,
|
|
11
|
+
additional_info: Optional[Dict[str, Any]] = None
|
|
12
|
+
):
|
|
13
|
+
self.resource_type = resource_type
|
|
14
|
+
self.resource_id = resource_id
|
|
15
|
+
self.additional_info = additional_info or {}
|
|
16
|
+
|
|
17
|
+
# Build detailed message
|
|
18
|
+
detail_msg = f"{detail}"
|
|
19
|
+
if resource_type:
|
|
20
|
+
detail_msg += f" [Resource Type: {resource_type}]"
|
|
21
|
+
if resource_id:
|
|
22
|
+
detail_msg += f" [ID: {resource_id}]"
|
|
23
|
+
|
|
24
|
+
super().__init__(status_code=status_code, detail=detail_msg)
|
|
25
|
+
|
|
26
|
+
class ResourceNotFoundError(BaseServiceException):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
resource_type: str,
|
|
30
|
+
resource_id: str,
|
|
31
|
+
additional_info: Optional[Dict[str, Any]] = None
|
|
32
|
+
):
|
|
33
|
+
super().__init__(
|
|
34
|
+
status_code=404,
|
|
35
|
+
detail="Resource not found",
|
|
36
|
+
resource_type=resource_type,
|
|
37
|
+
resource_id=resource_id,
|
|
38
|
+
additional_info=additional_info
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
class AuthorizationError(BaseServiceException):
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
resource_type: str,
|
|
45
|
+
action: str,
|
|
46
|
+
resource_id: Optional[str] = None,
|
|
47
|
+
additional_info: Optional[Dict[str, Any]] = None
|
|
48
|
+
):
|
|
49
|
+
super().__init__(
|
|
50
|
+
status_code=403,
|
|
51
|
+
detail=f"Not authorized to {action}",
|
|
52
|
+
resource_type=resource_type,
|
|
53
|
+
resource_id=resource_id,
|
|
54
|
+
additional_info=additional_info
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
class ValidationError(BaseServiceException):
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
resource_type: str,
|
|
61
|
+
detail: str,
|
|
62
|
+
resource_id: Optional[str] = None,
|
|
63
|
+
additional_info: Optional[Dict[str, Any]] = None
|
|
64
|
+
):
|
|
65
|
+
super().__init__(
|
|
66
|
+
status_code=422,
|
|
67
|
+
detail=detail,
|
|
68
|
+
resource_type=resource_type,
|
|
69
|
+
resource_id=resource_id,
|
|
70
|
+
additional_info=additional_info
|
|
71
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Generic, TypeVar, Optional, Any, Dict, List
|
|
2
|
+
from pydantic import BaseModel, ConfigDict
|
|
3
|
+
import datetime as dt
|
|
4
|
+
|
|
5
|
+
T = TypeVar('T')
|
|
6
|
+
|
|
7
|
+
class StandardResponse(BaseModel, Generic[T]):
|
|
8
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
9
|
+
success: bool
|
|
10
|
+
data: Optional[T] = None
|
|
11
|
+
message: Optional[str] = None
|
|
12
|
+
error: Optional[str] = None
|
|
13
|
+
|
|
14
|
+
metadata: Dict[str, Any] = {
|
|
15
|
+
"timestamp": dt.datetime.now(dt.timezone.utc).isoformat()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class PaginatedResponse(StandardResponse, Generic[T]):
|
|
19
|
+
total_count: int
|
|
20
|
+
page: int
|
|
21
|
+
page_size: int
|
|
22
|
+
items: List[T]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .base_service import BaseFirestoreService
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from typing import Dict, Any, Optional
|
|
2
|
+
from datetime import datetime,timezone
|
|
3
|
+
from fastapi import HTTPException
|
|
4
|
+
from google.cloud import firestore
|
|
5
|
+
from ..exceptions import ResourceNotFoundError, ValidationError
|
|
6
|
+
|
|
7
|
+
class BaseFirestoreService:
|
|
8
|
+
def __init__(self, db: firestore.Client, collection_name: str, resource_type: str):
|
|
9
|
+
self.db = db
|
|
10
|
+
self.collection_name = collection_name
|
|
11
|
+
self.resource_type = resource_type
|
|
12
|
+
|
|
13
|
+
def _validate_update_fields(self, update_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
14
|
+
"""Centralized update fields validation"""
|
|
15
|
+
if not isinstance(update_data, dict):
|
|
16
|
+
update_data = update_data.model_dump(exclude_unset=True)
|
|
17
|
+
|
|
18
|
+
valid_fields = {
|
|
19
|
+
k: v for k, v in update_data.items()
|
|
20
|
+
if v is not None and not (isinstance(v, (list, dict, set)) and len(v) == 0)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if not valid_fields:
|
|
24
|
+
raise ValidationError(
|
|
25
|
+
resource_type=self.resource_type,
|
|
26
|
+
detail="No valid fields to update",
|
|
27
|
+
resource_id=None
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return valid_fields
|
|
31
|
+
|
|
32
|
+
async def get_document(self, doc_id: str) -> Dict[str, Any]:
|
|
33
|
+
"""Get a document by ID with standardized error handling"""
|
|
34
|
+
doc_ref = self.db.collection(self.collection_name).document(doc_id)
|
|
35
|
+
doc = doc_ref.get()
|
|
36
|
+
|
|
37
|
+
if not doc.exists:
|
|
38
|
+
raise ResourceNotFoundError(
|
|
39
|
+
resource_type=self.resource_type,
|
|
40
|
+
resource_id=doc_id,
|
|
41
|
+
additional_info={"collection": self.collection_name}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return doc.to_dict()
|
|
45
|
+
|
|
46
|
+
async def update_document(self, doc_id: str, update_data: Dict[str, Any], user_uid: Optional[str] = None) -> Dict[str, Any]:
|
|
47
|
+
"""Standard update method with validation and audit fields"""
|
|
48
|
+
try:
|
|
49
|
+
doc_ref = self.db.collection(self.collection_name).document(doc_id)
|
|
50
|
+
|
|
51
|
+
if not doc_ref.get().exists:
|
|
52
|
+
raise ResourceNotFoundError(
|
|
53
|
+
resource_type=self.resource_type,
|
|
54
|
+
resource_id=doc_id,
|
|
55
|
+
additional_info={"collection": self.collection_name}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
valid_fields = self._validate_update_fields(update_data)
|
|
59
|
+
|
|
60
|
+
# Add audit fields
|
|
61
|
+
valid_fields.update({
|
|
62
|
+
'updt_date': datetime.now(timezone.utc).isoformat(),
|
|
63
|
+
'updt_by_user': user_uid if user_uid else None
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
doc_ref.update(valid_fields)
|
|
67
|
+
return doc_ref.get().to_dict()
|
|
68
|
+
|
|
69
|
+
except (ResourceNotFoundError, ValidationError):
|
|
70
|
+
raise
|
|
71
|
+
except Exception as e:
|
|
72
|
+
raise HTTPException(
|
|
73
|
+
status_code=500,
|
|
74
|
+
detail=f"Failed to update {self.resource_type}: {str(e)}"
|
|
75
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.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
|
|
@@ -3,16 +3,20 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
setup.py
|
|
5
5
|
src/ipulse_shared_core_ftredge/__init__.py
|
|
6
|
+
src/ipulse_shared_core_ftredge/exceptions.py
|
|
6
7
|
src/ipulse_shared_core_ftredge.egg-info/PKG-INFO
|
|
7
8
|
src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt
|
|
8
9
|
src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt
|
|
9
10
|
src/ipulse_shared_core_ftredge.egg-info/requires.txt
|
|
10
11
|
src/ipulse_shared_core_ftredge.egg-info/top_level.txt
|
|
11
12
|
src/ipulse_shared_core_ftredge/models/__init__.py
|
|
13
|
+
src/ipulse_shared_core_ftredge/models/api_response.py
|
|
12
14
|
src/ipulse_shared_core_ftredge/models/organisation.py
|
|
13
15
|
src/ipulse_shared_core_ftredge/models/resource_catalog_item.py
|
|
14
16
|
src/ipulse_shared_core_ftredge/models/user_auth.py
|
|
15
17
|
src/ipulse_shared_core_ftredge/models/user_profile.py
|
|
16
18
|
src/ipulse_shared_core_ftredge/models/user_profile_update.py
|
|
17
19
|
src/ipulse_shared_core_ftredge/models/user_status.py
|
|
20
|
+
src/ipulse_shared_core_ftredge/services/__init__.py
|
|
21
|
+
src/ipulse_shared_core_ftredge/services/base_service.py
|
|
18
22
|
tests/test_utils_gcp.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
|
{ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/tests/test_utils_gcp.py
RENAMED
|
File without changes
|