trovesuite 1.0.5__tar.gz → 1.0.7__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.
- {trovesuite-1.0.5/src/trovesuite.egg-info → trovesuite-1.0.7}/PKG-INFO +57 -3
- {trovesuite-1.0.5 → trovesuite-1.0.7}/README.md +52 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/pyproject.toml +11 -7
- {trovesuite-1.0.5 → trovesuite-1.0.7}/setup.py +1 -1
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/__init__.py +7 -4
- trovesuite-1.0.7/src/trovesuite/auth/auth_controller.py +11 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/configs/database.py +104 -22
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/entities/health.py +4 -4
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_controller.py +5 -5
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_read_dto.py +1 -1
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_service.py +3 -3
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_write_dto.py +1 -1
- trovesuite-1.0.7/src/trovesuite/storage/__init__.py +42 -0
- trovesuite-1.0.7/src/trovesuite/storage/storage_base.py +63 -0
- trovesuite-1.0.7/src/trovesuite/storage/storage_controller.py +198 -0
- trovesuite-1.0.7/src/trovesuite/storage/storage_read_dto.py +74 -0
- trovesuite-1.0.7/src/trovesuite/storage/storage_service.py +529 -0
- trovesuite-1.0.7/src/trovesuite/storage/storage_write_dto.py +70 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7/src/trovesuite.egg-info}/PKG-INFO +57 -3
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite.egg-info/SOURCES.txt +6 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite.egg-info/requires.txt +2 -0
- trovesuite-1.0.5/src/trovesuite/auth/auth_controller.py +0 -11
- {trovesuite-1.0.5 → trovesuite-1.0.7}/LICENSE +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/MANIFEST.in +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/requirements.txt +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/setup.cfg +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/auth/__init__.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/auth/auth_base.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/auth/auth_read_dto.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/auth/auth_service.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/auth/auth_write_dto.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/configs/__init__.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/configs/logging.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/configs/settings.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/entities/__init__.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/entities/sh_response.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/__init__.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_base.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/utils/__init__.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/utils/helper.py +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite.egg-info/dependency_links.txt +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite.egg-info/not-zip-safe +0 -0
- {trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trovesuite
|
|
3
|
-
Version: 1.0.
|
|
4
|
-
Summary: TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications
|
|
3
|
+
Version: 1.0.7
|
|
4
|
+
Summary: TroveSuite services package providing authentication, authorization, notifications, Azure Storage, and other enterprise services for TroveSuite applications
|
|
5
5
|
Home-page: https://dev.azure.com/brightgclt/trovesuite/_git/packages
|
|
6
6
|
Author: Bright Debrah Owusu
|
|
7
7
|
Author-email: Bright Debrah Owusu <owusu.debrah@deladetech.com>
|
|
@@ -11,7 +11,7 @@ Project-URL: Homepage, https://dev.azure.com/brightgclt/trovesuite/_git/packages
|
|
|
11
11
|
Project-URL: Repository, https://dev.azure.com/brightgclt/trovesuite/_git/packages
|
|
12
12
|
Project-URL: Documentation, https://dev.azure.com/brightgclt/trovesuite/_git/packages
|
|
13
13
|
Project-URL: Bug Tracker, https://dev.azure.com/brightgclt/trovesuite/_workitems/create
|
|
14
|
-
Keywords: authentication,authorization,notifications,jwt,trovesuite,fastapi,security,tenant,permissions,enterprise,services
|
|
14
|
+
Keywords: authentication,authorization,notifications,jwt,trovesuite,fastapi,security,tenant,permissions,enterprise,services,azure,storage,blob,cloud-storage
|
|
15
15
|
Classifier: Development Status :: 5 - Production/Stable
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
17
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -36,6 +36,8 @@ Requires-Dist: passlib[bcrypt]>=1.7.4
|
|
|
36
36
|
Requires-Dist: passlib[argon2]<2.0.0,>=1.7.4
|
|
37
37
|
Requires-Dist: uvicorn<0.39.0,>=0.38.0
|
|
38
38
|
Requires-Dist: pyjwt<3.0.0,>=2.10.1
|
|
39
|
+
Requires-Dist: azure-storage-blob>=12.19.0
|
|
40
|
+
Requires-Dist: azure-identity>=1.15.0
|
|
39
41
|
Provides-Extra: dev
|
|
40
42
|
Requires-Dist: pytest>=8.4.2; extra == "dev"
|
|
41
43
|
Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
|
|
@@ -119,6 +121,8 @@ poetry install --with dev
|
|
|
119
121
|
|
|
120
122
|
## Quick Start
|
|
121
123
|
|
|
124
|
+
> **✅ Package Status**: All import issues have been resolved in version 1.0.5. The package now works correctly when installed from PyPI or wheel files.
|
|
125
|
+
|
|
122
126
|
### Import Patterns
|
|
123
127
|
|
|
124
128
|
The package provides clean, simplified import patterns:
|
|
@@ -673,12 +677,62 @@ poetry install
|
|
|
673
677
|
|
|
674
678
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
675
679
|
|
|
680
|
+
## Troubleshooting
|
|
681
|
+
|
|
682
|
+
### Import Issues
|
|
683
|
+
|
|
684
|
+
If you encounter import errors, make sure you're using the correct import patterns:
|
|
685
|
+
|
|
686
|
+
```python
|
|
687
|
+
# ✅ Correct imports
|
|
688
|
+
from trovesuite import AuthService, NotificationService
|
|
689
|
+
from trovesuite.auth import AuthServiceWriteDto
|
|
690
|
+
from trovesuite.notification import NotificationEmailServiceWriteDto
|
|
691
|
+
|
|
692
|
+
# ❌ Incorrect imports (will fail)
|
|
693
|
+
from trovesuite.auth.auth_write_dto import AuthServiceWriteDto # Too specific
|
|
694
|
+
from trovesuite.notification.notification_write_dto import NotificationEmailServiceWriteDto # Too specific
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Package Installation
|
|
698
|
+
|
|
699
|
+
If you're having issues with the package installation:
|
|
700
|
+
|
|
701
|
+
1. **Make sure you have the latest version**:
|
|
702
|
+
```bash
|
|
703
|
+
pip install --upgrade trovesuite
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
2. **Force reinstall if needed**:
|
|
707
|
+
```bash
|
|
708
|
+
pip install --force-reinstall trovesuite
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
3. **Check your Python environment**:
|
|
712
|
+
```bash
|
|
713
|
+
python -c "import trovesuite; print('Package installed successfully')"
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Common Issues
|
|
717
|
+
|
|
718
|
+
- **ImportError: No module named 'src'**: This was fixed in version 1.0.5. Update to the latest version.
|
|
719
|
+
- **AttributeError: module has no attribute 'AuthServiceWriteDto'**: Use `from trovesuite.auth import AuthServiceWriteDto` instead of importing from the main package.
|
|
720
|
+
|
|
676
721
|
## Support
|
|
677
722
|
|
|
678
723
|
For support, email brightgclt@gmail.com or create a work item in the [Azure DevOps repository](https://dev.azure.com/brightgclt/trovesuite/_workitems/create).
|
|
679
724
|
|
|
680
725
|
## Changelog
|
|
681
726
|
|
|
727
|
+
### 1.0.5
|
|
728
|
+
- Fixed all import issues across auth, notification, and entities modules
|
|
729
|
+
- Changed absolute imports (`from src.trovesuite.`) to relative imports (`from .` and `from ..`)
|
|
730
|
+
- Ensured package works correctly when installed from PyPI or wheel
|
|
731
|
+
- Added service write DTOs to module exports for easier usage
|
|
732
|
+
- Updated documentation with simplified import patterns
|
|
733
|
+
- All services and DTOs now import correctly in clean environments
|
|
734
|
+
- Package builds and installs without import errors
|
|
735
|
+
|
|
682
736
|
### 1.0.8
|
|
683
737
|
- Restructured package for direct service imports
|
|
684
738
|
- Added comprehensive notification services with email support
|
|
@@ -66,6 +66,8 @@ poetry install --with dev
|
|
|
66
66
|
|
|
67
67
|
## Quick Start
|
|
68
68
|
|
|
69
|
+
> **✅ Package Status**: All import issues have been resolved in version 1.0.5. The package now works correctly when installed from PyPI or wheel files.
|
|
70
|
+
|
|
69
71
|
### Import Patterns
|
|
70
72
|
|
|
71
73
|
The package provides clean, simplified import patterns:
|
|
@@ -620,12 +622,62 @@ poetry install
|
|
|
620
622
|
|
|
621
623
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
622
624
|
|
|
625
|
+
## Troubleshooting
|
|
626
|
+
|
|
627
|
+
### Import Issues
|
|
628
|
+
|
|
629
|
+
If you encounter import errors, make sure you're using the correct import patterns:
|
|
630
|
+
|
|
631
|
+
```python
|
|
632
|
+
# ✅ Correct imports
|
|
633
|
+
from trovesuite import AuthService, NotificationService
|
|
634
|
+
from trovesuite.auth import AuthServiceWriteDto
|
|
635
|
+
from trovesuite.notification import NotificationEmailServiceWriteDto
|
|
636
|
+
|
|
637
|
+
# ❌ Incorrect imports (will fail)
|
|
638
|
+
from trovesuite.auth.auth_write_dto import AuthServiceWriteDto # Too specific
|
|
639
|
+
from trovesuite.notification.notification_write_dto import NotificationEmailServiceWriteDto # Too specific
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Package Installation
|
|
643
|
+
|
|
644
|
+
If you're having issues with the package installation:
|
|
645
|
+
|
|
646
|
+
1. **Make sure you have the latest version**:
|
|
647
|
+
```bash
|
|
648
|
+
pip install --upgrade trovesuite
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
2. **Force reinstall if needed**:
|
|
652
|
+
```bash
|
|
653
|
+
pip install --force-reinstall trovesuite
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
3. **Check your Python environment**:
|
|
657
|
+
```bash
|
|
658
|
+
python -c "import trovesuite; print('Package installed successfully')"
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Common Issues
|
|
662
|
+
|
|
663
|
+
- **ImportError: No module named 'src'**: This was fixed in version 1.0.5. Update to the latest version.
|
|
664
|
+
- **AttributeError: module has no attribute 'AuthServiceWriteDto'**: Use `from trovesuite.auth import AuthServiceWriteDto` instead of importing from the main package.
|
|
665
|
+
|
|
623
666
|
## Support
|
|
624
667
|
|
|
625
668
|
For support, email brightgclt@gmail.com or create a work item in the [Azure DevOps repository](https://dev.azure.com/brightgclt/trovesuite/_workitems/create).
|
|
626
669
|
|
|
627
670
|
## Changelog
|
|
628
671
|
|
|
672
|
+
### 1.0.5
|
|
673
|
+
- Fixed all import issues across auth, notification, and entities modules
|
|
674
|
+
- Changed absolute imports (`from src.trovesuite.`) to relative imports (`from .` and `from ..`)
|
|
675
|
+
- Ensured package works correctly when installed from PyPI or wheel
|
|
676
|
+
- Added service write DTOs to module exports for easier usage
|
|
677
|
+
- Updated documentation with simplified import patterns
|
|
678
|
+
- All services and DTOs now import correctly in clean environments
|
|
679
|
+
- Package builds and installs without import errors
|
|
680
|
+
|
|
629
681
|
### 1.0.8
|
|
630
682
|
- Restructured package for direct service imports
|
|
631
683
|
- Added comprehensive notification services with email support
|
|
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "trovesuite"
|
|
7
|
-
version = "1.0.
|
|
8
|
-
description = "TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications"
|
|
7
|
+
version = "1.0.7"
|
|
8
|
+
description = "TroveSuite services package providing authentication, authorization, notifications, Azure Storage, and other enterprise services for TroveSuite applications"
|
|
9
9
|
authors = ["brightgclt <brightgclt@gmail.com>"]
|
|
10
10
|
license = "MIT"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
homepage = "https://dev.azure.com/brightgclt/trovesuite/_git/packages"
|
|
13
13
|
repository = "https://dev.azure.com/brightgclt/trovesuite/_git/packages"
|
|
14
14
|
documentation = "https://dev.azure.com/brightgclt/trovesuite/_git/packages"
|
|
15
|
-
keywords = ["authentication", "authorization", "notifications", "jwt", "trovesuite", "fastapi", "security", "tenant", "permissions", "enterprise", "services"]
|
|
15
|
+
keywords = ["authentication", "authorization", "notifications", "jwt", "trovesuite", "fastapi", "security", "tenant", "permissions", "enterprise", "services", "azure", "storage", "blob", "cloud-storage"]
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 5 - Production/Stable",
|
|
18
18
|
"Intended Audience :: Developers",
|
|
@@ -36,6 +36,8 @@ python-dotenv = "^1.0.0"
|
|
|
36
36
|
python-multipart = "^0.0.6"
|
|
37
37
|
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
|
|
38
38
|
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
|
|
39
|
+
azure-storage-blob = "^12.19.0"
|
|
40
|
+
azure-identity = "^1.15.0"
|
|
39
41
|
|
|
40
42
|
[tool.poetry.group.dev.dependencies]
|
|
41
43
|
pytest = "^8.4.2"
|
|
@@ -56,8 +58,8 @@ Documentation = "https://dev.azure.com/brightgclt/trovesuite/_git/packages"
|
|
|
56
58
|
|
|
57
59
|
[project]
|
|
58
60
|
name = "trovesuite"
|
|
59
|
-
version = "1.0.
|
|
60
|
-
description = "TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications"
|
|
61
|
+
version = "1.0.7"
|
|
62
|
+
description = "TroveSuite services package providing authentication, authorization, notifications, Azure Storage, and other enterprise services for TroveSuite applications"
|
|
61
63
|
readme = "README.md"
|
|
62
64
|
license = {text = "MIT"}
|
|
63
65
|
authors = [
|
|
@@ -66,7 +68,7 @@ authors = [
|
|
|
66
68
|
maintainers = [
|
|
67
69
|
{name = "Bright Debrah Owusu", email = "owusu.debrah@deladetech.com"}
|
|
68
70
|
]
|
|
69
|
-
keywords = ["authentication", "authorization", "notifications", "jwt", "trovesuite", "fastapi", "security", "tenant", "permissions", "enterprise", "services"]
|
|
71
|
+
keywords = ["authentication", "authorization", "notifications", "jwt", "trovesuite", "fastapi", "security", "tenant", "permissions", "enterprise", "services", "azure", "storage", "blob", "cloud-storage"]
|
|
70
72
|
classifiers = [
|
|
71
73
|
"Development Status :: 5 - Production/Stable",
|
|
72
74
|
"Intended Audience :: Developers",
|
|
@@ -91,7 +93,9 @@ dependencies = [
|
|
|
91
93
|
"passlib[bcrypt]>=1.7.4",
|
|
92
94
|
"passlib[argon2] (>=1.7.4,<2.0.0)",
|
|
93
95
|
"uvicorn (>=0.38.0,<0.39.0)",
|
|
94
|
-
"pyjwt (>=2.10.1,<3.0.0)"
|
|
96
|
+
"pyjwt (>=2.10.1,<3.0.0)",
|
|
97
|
+
"azure-storage-blob>=12.19.0",
|
|
98
|
+
"azure-identity>=1.15.0"
|
|
95
99
|
|
|
96
100
|
]
|
|
97
101
|
|
|
@@ -15,7 +15,7 @@ with open("pyproject.toml", "r", encoding="utf-8") as fh:
|
|
|
15
15
|
|
|
16
16
|
setup(
|
|
17
17
|
name="trovesuite",
|
|
18
|
-
version="1.0.
|
|
18
|
+
version="1.0.7",
|
|
19
19
|
author="Bright Debrah Owusu",
|
|
20
20
|
author_email="owusu.debrah@deladetech.com",
|
|
21
21
|
description="TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications",
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"""
|
|
2
2
|
TroveSuite Package
|
|
3
3
|
|
|
4
|
-
A comprehensive authentication, authorization, and
|
|
5
|
-
Provides JWT token validation, user authorization, permission checking,
|
|
4
|
+
A comprehensive authentication, authorization, notification, and storage service for ERP systems.
|
|
5
|
+
Provides JWT token validation, user authorization, permission checking, notification capabilities,
|
|
6
|
+
and Azure Storage blob management.
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from .auth import AuthService
|
|
9
10
|
from .notification import NotificationService
|
|
11
|
+
from .storage import StorageService
|
|
10
12
|
|
|
11
|
-
__version__ = "1.0.
|
|
13
|
+
__version__ = "1.0.7"
|
|
12
14
|
__author__ = "Bright Debrah Owusu"
|
|
13
15
|
__email__ = "owusu.debrah@deladetech.com"
|
|
14
16
|
|
|
15
17
|
__all__ = [
|
|
16
18
|
"AuthService",
|
|
17
|
-
"NotificationService"
|
|
19
|
+
"NotificationService",
|
|
20
|
+
"StorageService"
|
|
18
21
|
]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from fastapi import APIRouter
|
|
2
|
+
from .auth_write_dto import AuthControllerWriteDto
|
|
3
|
+
from .auth_read_dto import AuthControllerReadDto
|
|
4
|
+
from .auth_service import AuthService
|
|
5
|
+
from ..entities.sh_response import Respons
|
|
6
|
+
|
|
7
|
+
auth_router = APIRouter(tags=["Auth"])
|
|
8
|
+
|
|
9
|
+
@auth_router.post("/auth", response_model=Respons[AuthControllerReadDto])
|
|
10
|
+
async def authorize(data: AuthControllerWriteDto):
|
|
11
|
+
return AuthService.authorize(data=data)
|
|
@@ -17,20 +17,25 @@ _connection_pool: Optional[psycopg2.pool.ThreadedConnectionPool] = None
|
|
|
17
17
|
|
|
18
18
|
class DatabaseConfig:
|
|
19
19
|
"""Database configuration and connection management"""
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def __init__(self):
|
|
22
22
|
self.settings = db_settings
|
|
23
23
|
self.database_url = self.settings.database_url
|
|
24
24
|
self.pool_size = 5
|
|
25
25
|
self.max_overflow = 10
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
def get_connection_params(self) -> dict:
|
|
28
28
|
"""Get database connection parameters"""
|
|
29
29
|
if self.settings.DATABASE_URL:
|
|
30
30
|
# Use full DATABASE_URL if available
|
|
31
31
|
return {
|
|
32
32
|
"dsn": self.settings.DATABASE_URL,
|
|
33
|
-
"cursor_factory": RealDictCursor
|
|
33
|
+
"cursor_factory": RealDictCursor,
|
|
34
|
+
"keepalives": 1,
|
|
35
|
+
"keepalives_idle": 30,
|
|
36
|
+
"keepalives_interval": 10,
|
|
37
|
+
"keepalives_count": 5,
|
|
38
|
+
"connect_timeout": 10
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
# fallback to individual DB_* variables
|
|
@@ -41,9 +46,14 @@ class DatabaseConfig:
|
|
|
41
46
|
"user": self.settings.DB_USER,
|
|
42
47
|
"password": self.settings.DB_PASSWORD,
|
|
43
48
|
"cursor_factory": RealDictCursor,
|
|
44
|
-
"application_name": f"{self.settings.APP_NAME}_{self.settings.ENVIRONMENT}"
|
|
49
|
+
"application_name": f"{self.settings.APP_NAME}_{self.settings.ENVIRONMENT}",
|
|
50
|
+
"keepalives": 1,
|
|
51
|
+
"keepalives_idle": 30,
|
|
52
|
+
"keepalives_interval": 10,
|
|
53
|
+
"keepalives_count": 5,
|
|
54
|
+
"connect_timeout": 10
|
|
45
55
|
}
|
|
46
|
-
|
|
56
|
+
|
|
47
57
|
def create_connection_pool(self) -> psycopg2.pool.ThreadedConnectionPool:
|
|
48
58
|
"""Create a connection pool for psycopg2"""
|
|
49
59
|
try:
|
|
@@ -57,7 +67,7 @@ class DatabaseConfig:
|
|
|
57
67
|
except Exception as e:
|
|
58
68
|
logger.error(f"Failed to create database connection pool: {str(e)}")
|
|
59
69
|
raise
|
|
60
|
-
|
|
70
|
+
|
|
61
71
|
def test_connection(self) -> bool:
|
|
62
72
|
"""Test database connection"""
|
|
63
73
|
try:
|
|
@@ -81,17 +91,17 @@ db_config = DatabaseConfig()
|
|
|
81
91
|
def initialize_database():
|
|
82
92
|
"""Initialize database connections and pool"""
|
|
83
93
|
global _connection_pool
|
|
84
|
-
|
|
94
|
+
|
|
85
95
|
try:
|
|
86
96
|
# Test connection first
|
|
87
97
|
if not db_config.test_connection():
|
|
88
98
|
raise Exception("Database connection test failed")
|
|
89
|
-
|
|
99
|
+
|
|
90
100
|
# Create connection pool
|
|
91
101
|
_connection_pool = db_config.create_connection_pool()
|
|
92
|
-
|
|
102
|
+
|
|
93
103
|
logger.info("Database initialization completed successfully")
|
|
94
|
-
|
|
104
|
+
|
|
95
105
|
except Exception as e:
|
|
96
106
|
logger.error(f"Database initialization failed: {str(e)}")
|
|
97
107
|
raise
|
|
@@ -114,6 +124,17 @@ def get_connection_pool() -> psycopg2.pool.ThreadedConnectionPool:
|
|
|
114
124
|
return _connection_pool
|
|
115
125
|
|
|
116
126
|
|
|
127
|
+
def _validate_connection(conn) -> bool:
|
|
128
|
+
"""Validate if a connection is still alive"""
|
|
129
|
+
try:
|
|
130
|
+
# Test if connection is alive with a simple query
|
|
131
|
+
with conn.cursor() as cursor:
|
|
132
|
+
cursor.execute("SELECT 1")
|
|
133
|
+
return True
|
|
134
|
+
except (psycopg2.OperationalError, psycopg2.InterfaceError):
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
|
|
117
138
|
@contextmanager
|
|
118
139
|
def get_db_connection():
|
|
119
140
|
"""Get a database connection from the pool (context manager)"""
|
|
@@ -121,52 +142,79 @@ def get_db_connection():
|
|
|
121
142
|
conn = None
|
|
122
143
|
try:
|
|
123
144
|
conn = pool.getconn()
|
|
145
|
+
|
|
146
|
+
# Validate connection before using it
|
|
147
|
+
if not _validate_connection(conn):
|
|
148
|
+
logger.warning("Stale connection detected, getting new connection")
|
|
149
|
+
pool.putconn(conn, close=True)
|
|
150
|
+
conn = pool.getconn()
|
|
151
|
+
|
|
124
152
|
logger.debug("Database connection acquired from pool")
|
|
125
153
|
yield conn
|
|
126
154
|
except Exception as e:
|
|
127
155
|
logger.error(f"Database connection error: {str(e)}")
|
|
128
156
|
if conn:
|
|
129
|
-
|
|
157
|
+
try:
|
|
158
|
+
# Only rollback if connection is still open
|
|
159
|
+
if not conn.closed:
|
|
160
|
+
conn.rollback()
|
|
161
|
+
except (psycopg2.OperationalError, psycopg2.InterfaceError) as rollback_error:
|
|
162
|
+
logger.warning(f"Could not rollback closed connection: {str(rollback_error)}")
|
|
130
163
|
raise
|
|
131
164
|
finally:
|
|
132
165
|
if conn:
|
|
133
|
-
|
|
134
|
-
|
|
166
|
+
try:
|
|
167
|
+
# If connection is broken, close it instead of returning to pool
|
|
168
|
+
if conn.closed:
|
|
169
|
+
pool.putconn(conn, close=True)
|
|
170
|
+
else:
|
|
171
|
+
pool.putconn(conn)
|
|
172
|
+
logger.debug("Database connection returned to pool")
|
|
173
|
+
except Exception as put_error:
|
|
174
|
+
logger.error(f"Error returning connection to pool: {str(put_error)}")
|
|
135
175
|
|
|
136
176
|
|
|
137
177
|
@contextmanager
|
|
138
178
|
def get_db_cursor():
|
|
139
179
|
"""Get a database cursor (context manager)"""
|
|
140
180
|
with get_db_connection() as conn:
|
|
141
|
-
cursor = conn.cursor()
|
|
181
|
+
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
|
142
182
|
try:
|
|
143
183
|
yield cursor
|
|
144
|
-
conn.
|
|
184
|
+
if not conn.closed:
|
|
185
|
+
conn.commit()
|
|
145
186
|
except Exception as e:
|
|
146
|
-
conn.
|
|
187
|
+
if not conn.closed:
|
|
188
|
+
try:
|
|
189
|
+
conn.rollback()
|
|
190
|
+
except (psycopg2.OperationalError, psycopg2.InterfaceError) as rollback_error:
|
|
191
|
+
logger.warning(f"Could not rollback transaction on closed connection: {str(rollback_error)}")
|
|
147
192
|
logger.error(f"Database cursor error: {str(e)}")
|
|
148
193
|
raise
|
|
149
194
|
finally:
|
|
150
|
-
|
|
195
|
+
try:
|
|
196
|
+
cursor.close()
|
|
197
|
+
except Exception as close_error:
|
|
198
|
+
logger.warning(f"Error closing cursor: {str(close_error)}")
|
|
151
199
|
|
|
152
200
|
|
|
153
201
|
class DatabaseManager:
|
|
154
202
|
"""Database manager for common operations"""
|
|
155
|
-
|
|
203
|
+
|
|
156
204
|
@staticmethod
|
|
157
205
|
def execute_query(query: str, params: tuple = None) -> list:
|
|
158
206
|
"""Execute a SELECT query and return results"""
|
|
159
207
|
with get_db_cursor() as cursor:
|
|
160
208
|
cursor.execute(query, params)
|
|
161
209
|
return cursor.fetchall()
|
|
162
|
-
|
|
210
|
+
|
|
163
211
|
@staticmethod
|
|
164
212
|
def execute_update(query: str, params: tuple = None) -> int:
|
|
165
213
|
"""Execute an INSERT/UPDATE/DELETE query and return affected rows"""
|
|
166
214
|
with get_db_cursor() as cursor:
|
|
167
215
|
cursor.execute(query, params)
|
|
168
216
|
return cursor.rowcount
|
|
169
|
-
|
|
217
|
+
|
|
170
218
|
@staticmethod
|
|
171
219
|
def execute_scalar(query: str, params: tuple = None):
|
|
172
220
|
"""Execute a query and return a single value"""
|
|
@@ -182,7 +230,41 @@ class DatabaseManager:
|
|
|
182
230
|
# Handle tuple result
|
|
183
231
|
return result[0] if len(result) > 0 else None
|
|
184
232
|
return None
|
|
185
|
-
|
|
233
|
+
|
|
234
|
+
@staticmethod
|
|
235
|
+
@contextmanager
|
|
236
|
+
def transaction():
|
|
237
|
+
"""
|
|
238
|
+
Context manager for database transactions.
|
|
239
|
+
Wraps multiple operations in a single transaction.
|
|
240
|
+
|
|
241
|
+
Usage:
|
|
242
|
+
with DatabaseManager.transaction() as cursor:
|
|
243
|
+
cursor.execute("INSERT INTO table1 ...")
|
|
244
|
+
cursor.execute("INSERT INTO table2 ...")
|
|
245
|
+
# Auto-commits on success, auto-rollbacks on exception
|
|
246
|
+
"""
|
|
247
|
+
with get_db_connection() as conn:
|
|
248
|
+
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
|
249
|
+
try:
|
|
250
|
+
yield cursor
|
|
251
|
+
if not conn.closed:
|
|
252
|
+
conn.commit()
|
|
253
|
+
logger.debug("Transaction committed successfully")
|
|
254
|
+
except Exception as e:
|
|
255
|
+
if not conn.closed:
|
|
256
|
+
try:
|
|
257
|
+
conn.rollback()
|
|
258
|
+
logger.warning(f"Transaction rolled back due to error: {str(e)}")
|
|
259
|
+
except (psycopg2.OperationalError, psycopg2.InterfaceError) as rollback_error:
|
|
260
|
+
logger.error(f"Could not rollback transaction: {str(rollback_error)}")
|
|
261
|
+
raise
|
|
262
|
+
finally:
|
|
263
|
+
try:
|
|
264
|
+
cursor.close()
|
|
265
|
+
except Exception as close_error:
|
|
266
|
+
logger.warning(f"Error closing transaction cursor: {str(close_error)}")
|
|
267
|
+
|
|
186
268
|
@staticmethod
|
|
187
269
|
def health_check() -> dict:
|
|
188
270
|
"""Perform database health check"""
|
|
@@ -190,7 +272,7 @@ class DatabaseManager:
|
|
|
190
272
|
with get_db_cursor() as cursor:
|
|
191
273
|
cursor.execute("SELECT version(), current_database(), current_user")
|
|
192
274
|
result = cursor.fetchone()
|
|
193
|
-
|
|
275
|
+
|
|
194
276
|
if result:
|
|
195
277
|
# Handle RealDictRow (dictionary-like) result
|
|
196
278
|
if hasattr(result, 'get'):
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from fastapi import APIRouter
|
|
2
|
-
from
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from
|
|
2
|
+
from .sh_response import Respons
|
|
3
|
+
from ..configs.settings import db_settings
|
|
4
|
+
from ..configs.database import DatabaseManager
|
|
5
|
+
from ..configs.logging import get_logger
|
|
6
6
|
|
|
7
7
|
health_check_router = APIRouter(tags=["Health Path"])
|
|
8
8
|
logger = get_logger("health")
|
{trovesuite-1.0.5 → trovesuite-1.0.7}/src/trovesuite/notification/notification_controller.py
RENAMED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from
|
|
1
|
+
from .notification_write_dto import (
|
|
2
2
|
NotificationEmailControllerWriteDto,
|
|
3
3
|
NotificationSMSControllerWriteDto
|
|
4
4
|
)
|
|
5
|
-
from
|
|
5
|
+
from .notification_read_dto import (
|
|
6
6
|
NotificationEmailControllerReadDto,
|
|
7
7
|
NotificationSMSControllerReadDto
|
|
8
8
|
)
|
|
9
|
-
from
|
|
10
|
-
from
|
|
9
|
+
from .notification_service import NotificationService
|
|
10
|
+
from ..entities.sh_response import Respons
|
|
11
11
|
from fastapi import APIRouter
|
|
12
12
|
|
|
13
|
-
notification_router = APIRouter()
|
|
13
|
+
notification_router = APIRouter(tags=["Notification"])
|
|
14
14
|
|
|
15
15
|
@notification_router.post("/send_email", response_model=Respons[NotificationEmailControllerReadDto])
|
|
16
16
|
async def send_email(data: NotificationEmailControllerWriteDto):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import smtplib
|
|
2
2
|
from email.mime.text import MIMEText
|
|
3
3
|
from email.mime.multipart import MIMEMultipart
|
|
4
|
-
from
|
|
5
|
-
from
|
|
4
|
+
from ..entities.sh_response import Respons
|
|
5
|
+
from .notification_read_dto import (
|
|
6
6
|
NotificationEmailServiceReadDto,
|
|
7
7
|
NotificationSMSServiceReadDto
|
|
8
8
|
)
|
|
9
|
-
from
|
|
9
|
+
from .notification_write_dto import (
|
|
10
10
|
NotificationEmailServiceWriteDto,
|
|
11
11
|
NotificationSMSServiceWriteDto
|
|
12
12
|
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TroveSuite Storage Service
|
|
3
|
+
|
|
4
|
+
Provides Azure Storage blob management capabilities for TroveSuite applications.
|
|
5
|
+
Includes container creation, file upload/download/update/delete, and presigned URL generation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .storage_service import StorageService
|
|
9
|
+
from .storage_write_dto import (
|
|
10
|
+
StorageContainerCreateServiceWriteDto,
|
|
11
|
+
StorageFileUploadServiceWriteDto,
|
|
12
|
+
StorageFileUpdateServiceWriteDto,
|
|
13
|
+
StorageFileDeleteServiceWriteDto,
|
|
14
|
+
StorageFileDownloadServiceWriteDto,
|
|
15
|
+
StorageFileUrlServiceWriteDto
|
|
16
|
+
)
|
|
17
|
+
from .storage_read_dto import (
|
|
18
|
+
StorageContainerCreateServiceReadDto,
|
|
19
|
+
StorageFileUploadServiceReadDto,
|
|
20
|
+
StorageFileUpdateServiceReadDto,
|
|
21
|
+
StorageFileDeleteServiceReadDto,
|
|
22
|
+
StorageFileDownloadServiceReadDto,
|
|
23
|
+
StorageFileUrlServiceReadDto
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"StorageService",
|
|
28
|
+
# Write DTOs
|
|
29
|
+
"StorageContainerCreateServiceWriteDto",
|
|
30
|
+
"StorageFileUploadServiceWriteDto",
|
|
31
|
+
"StorageFileUpdateServiceWriteDto",
|
|
32
|
+
"StorageFileDeleteServiceWriteDto",
|
|
33
|
+
"StorageFileDownloadServiceWriteDto",
|
|
34
|
+
"StorageFileUrlServiceWriteDto",
|
|
35
|
+
# Read DTOs
|
|
36
|
+
"StorageContainerCreateServiceReadDto",
|
|
37
|
+
"StorageFileUploadServiceReadDto",
|
|
38
|
+
"StorageFileUpdateServiceReadDto",
|
|
39
|
+
"StorageFileDeleteServiceReadDto",
|
|
40
|
+
"StorageFileDownloadServiceReadDto",
|
|
41
|
+
"StorageFileUrlServiceReadDto",
|
|
42
|
+
]
|