trovesuite 1.0.2__tar.gz → 1.0.4__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.
Files changed (31) hide show
  1. {trovesuite-1.0.2/src/trovesuite.egg-info → trovesuite-1.0.4}/PKG-INFO +3 -1
  2. {trovesuite-1.0.2 → trovesuite-1.0.4}/pyproject.toml +5 -3
  3. {trovesuite-1.0.2 → trovesuite-1.0.4}/setup.py +1 -1
  4. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/auth_controller.py +2 -1
  5. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/auth_read_dto.py +0 -1
  6. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/auth_service.py +7 -7
  7. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/auth_write_dto.py +1 -1
  8. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/configs/database.py +29 -17
  9. trovesuite-1.0.4/src/trovesuite/configs/settings.py +57 -0
  10. {trovesuite-1.0.2 → trovesuite-1.0.4/src/trovesuite.egg-info}/PKG-INFO +3 -1
  11. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite.egg-info/requires.txt +2 -0
  12. trovesuite-1.0.2/src/trovesuite/configs/settings.py +0 -153
  13. {trovesuite-1.0.2 → trovesuite-1.0.4}/LICENSE +0 -0
  14. {trovesuite-1.0.2 → trovesuite-1.0.4}/MANIFEST.in +0 -0
  15. {trovesuite-1.0.2 → trovesuite-1.0.4}/README.md +0 -0
  16. {trovesuite-1.0.2 → trovesuite-1.0.4}/requirements.txt +0 -0
  17. {trovesuite-1.0.2 → trovesuite-1.0.4}/setup.cfg +0 -0
  18. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/__init__.py +0 -0
  19. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/__init__.py +0 -0
  20. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/auth/auth_base.py +0 -0
  21. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/configs/__init__.py +0 -0
  22. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/configs/logging.py +0 -0
  23. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/entities/__init__.py +0 -0
  24. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/entities/health.py +0 -0
  25. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/entities/sh_response.py +0 -0
  26. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/utils/__init__.py +0 -0
  27. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite/utils/helper.py +0 -0
  28. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite.egg-info/SOURCES.txt +0 -0
  29. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite.egg-info/dependency_links.txt +0 -0
  30. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite.egg-info/not-zip-safe +0 -0
  31. {trovesuite-1.0.2 → trovesuite-1.0.4}/src/trovesuite.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trovesuite
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: TroveSuite services package providing authentication, authorization, notifications, 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
@@ -34,6 +34,8 @@ Requires-Dist: python-multipart>=0.0.6
34
34
  Requires-Dist: python-jose[cryptography]>=3.3.0
35
35
  Requires-Dist: passlib[bcrypt]>=1.7.4
36
36
  Requires-Dist: passlib[argon2]<2.0.0,>=1.7.4
37
+ Requires-Dist: uvicorn<0.39.0,>=0.38.0
38
+ Requires-Dist: pyjwt<3.0.0,>=2.10.1
37
39
  Provides-Extra: dev
38
40
  Requires-Dist: pytest>=8.4.2; extra == "dev"
39
41
  Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "trovesuite"
7
- version = "1.0.2"
7
+ version = "1.0.4"
8
8
  description = "TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications"
9
9
  authors = ["brightgclt <brightgclt@gmail.com>"]
10
10
  license = "MIT"
@@ -56,7 +56,7 @@ Documentation = "https://dev.azure.com/brightgclt/trovesuite/_git/packages"
56
56
 
57
57
  [project]
58
58
  name = "trovesuite"
59
- version = "1.0.2"
59
+ version = "1.0.4"
60
60
  description = "TroveSuite services package providing authentication, authorization, notifications, and other enterprise services for TroveSuite applications"
61
61
  readme = "README.md"
62
62
  license = {text = "MIT"}
@@ -89,7 +89,9 @@ dependencies = [
89
89
  "python-multipart>=0.0.6",
90
90
  "python-jose[cryptography]>=3.3.0",
91
91
  "passlib[bcrypt]>=1.7.4",
92
- "passlib[argon2] (>=1.7.4,<2.0.0)"
92
+ "passlib[argon2] (>=1.7.4,<2.0.0)",
93
+ "uvicorn (>=0.38.0,<0.39.0)",
94
+ "pyjwt (>=2.10.1,<3.0.0)"
93
95
 
94
96
  ]
95
97
 
@@ -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.2",
18
+ version="1.0.4",
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",
@@ -2,9 +2,10 @@ from fastapi import APIRouter
2
2
  from src.trovesuite.auth.auth_write_dto import AuthControllerWriteDto
3
3
  from src.trovesuite.auth.auth_read_dto import AuthControllerReadDto
4
4
  from src.trovesuite.auth.auth_service import AuthService
5
+ from src.trovesuite.entities.sh_response import Respons
5
6
 
6
7
  auth_router = APIRouter()
7
8
 
8
- @auth_router.post("/auth", response_model=AuthControllerReadDto)
9
+ @auth_router.post("/auth", response_model=Respons[AuthControllerReadDto])
9
10
  async def authorize(data: AuthControllerWriteDto):
10
11
  return AuthService.authorize(data=data)
@@ -11,7 +11,6 @@ class AuthControllerReadDto(BaseModel):
11
11
  role_id: Optional[str] = None
12
12
  tenant_id: Optional[str] = None
13
13
  permissions: Optional[List[str]] = None
14
- shared_resource_id: Optional[str] = None
15
14
  resource_id: Optional[str] = None
16
15
 
17
16
  class AuthServiceReadDto(AuthControllerReadDto):
@@ -48,7 +48,7 @@ class AuthService:
48
48
 
49
49
  user_id: str = data.user_id
50
50
  tenant_id: str = data.tenant_id
51
-
51
+
52
52
  """Check if a user is authorized based on login settings and roles"""
53
53
  # Input validation
54
54
  if not user_id or not isinstance(user_id, str):
@@ -68,14 +68,14 @@ class AuthService:
68
68
  status_code=400,
69
69
  error="INVALID_TENANT_ID"
70
70
  )
71
-
71
+
72
72
  try:
73
73
 
74
74
  is_tenant_verified = DatabaseManager.execute_query(
75
75
  f"SELECT is_verified FROM {db_settings.MAIN_TENANTS_TABLE} WHERE delete_status = 'NOT_DELETED' AND id = %s",
76
76
  (tenant_id,),
77
77
  )
78
-
78
+
79
79
  if not is_tenant_verified or len(is_tenant_verified) == 0:
80
80
  logger.warning("Login failed - tenant not found: %s", tenant_id)
81
81
  return Respons[AuthServiceReadDto](
@@ -156,7 +156,7 @@ class AuthService:
156
156
 
157
157
  # 1️⃣ Get all groups the user belongs to
158
158
  user_groups = DatabaseManager.execute_query(
159
- f"""SELECT group_id FROM "{tenant_id}".{db_settings.USER_GROUPS_TABLE}
159
+ f"""SELECT group_id FROM "{tenant_id}".{db_settings.TENANT_USER_GROUPS_TABLE}
160
160
  WHERE delete_status = 'NOT_DELETED' AND is_active = true AND user_id = %s""",(user_id,),
161
161
  )
162
162
 
@@ -169,7 +169,7 @@ class AuthService:
169
169
  f"""
170
170
  SELECT DISTINCT ON (org_id, group_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id)
171
171
  org_id, group_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id
172
- FROM "{tenant_id}".{db_settings.ASSIGN_ROLES_TABLE}
172
+ FROM "{tenant_id}".{db_settings.TENANT_ASSIGN_ROLES_TABLE}
173
173
  WHERE delete_status = 'NOT_DELETED'
174
174
  AND is_active = true
175
175
  AND (user_id = %s OR group_id = ANY(%s))
@@ -183,7 +183,7 @@ class AuthService:
183
183
  f"""
184
184
  SELECT DISTINCT ON (org_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id)
185
185
  org_id, bus_id, app_id, shared_resource_id, resource_id, user_id, role_id
186
- FROM "{tenant_id}".{db_settings.ASSIGN_ROLES_TABLE}
186
+ FROM "{tenant_id}".{db_settings.TENANT_ASSIGN_ROLES_TABLE}
187
187
  WHERE delete_status = 'NOT_DELETED'
188
188
  AND is_active = true
189
189
  AND user_id = %s
@@ -196,7 +196,7 @@ class AuthService:
196
196
  get_user_roles_with_tenant_and_permissions = []
197
197
  for role in get_user_roles:
198
198
  permissions = DatabaseManager.execute_query(
199
- f"""SELECT permission_id FROM {db_settings.ROLE_PERMISSIONS_TABLE} WHERE role_id = %s""",
199
+ f"""SELECT permission_id FROM {db_settings.MAIN_ROLE_PERMISSIONS_TABLE} WHERE role_id = %s""",
200
200
  params=(role["role_id"],),)
201
201
 
202
202
  role_dict = {**role, "tenant_id": tenant_id, "permissions": [p['permission_id'] for p in permissions]}
@@ -4,7 +4,7 @@ from pydantic import BaseModel
4
4
 
5
5
  class AuthControllerWriteDto(BaseModel):
6
6
  user_id: Optional[str] = None
7
- tenant: Optional[str] = None
7
+ tenant_id: Optional[str] = None
8
8
 
9
9
  class AuthServiceWriteDto(AuthControllerWriteDto):
10
10
  pass
@@ -13,7 +13,6 @@ logger = get_logger("database")
13
13
 
14
14
  # Database connection pool
15
15
  _connection_pool: Optional[psycopg2.pool.ThreadedConnectionPool] = None
16
- _sqlmodel_engine = None
17
16
 
18
17
 
19
18
  class DatabaseConfig:
@@ -21,16 +20,20 @@ class DatabaseConfig:
21
20
 
22
21
  def __init__(self):
23
22
  self.settings = db_settings
23
+ self.database_url = self.settings.database_url
24
24
  self.pool_size = 5
25
25
  self.max_overflow = 10
26
-
27
- @property
28
- def database_url(self):
29
- """Get database URL (lazy evaluation)"""
30
- return self.settings.database_url
31
26
 
32
27
  def get_connection_params(self) -> dict:
33
28
  """Get database connection parameters"""
29
+ if self.settings.DATABASE_URL:
30
+ # Use full DATABASE_URL if available
31
+ return {
32
+ "dsn": self.settings.DATABASE_URL,
33
+ "cursor_factory": RealDictCursor
34
+ }
35
+
36
+ # fallback to individual DB_* variables
34
37
  return {
35
38
  "host": self.settings.DB_HOST,
36
39
  "port": self.settings.DB_PORT,
@@ -98,18 +101,19 @@ def get_connection_pool() -> psycopg2.pool.ThreadedConnectionPool:
98
101
  """Get the database connection pool"""
99
102
  global _connection_pool
100
103
  if _connection_pool is None:
101
- raise Exception("Database not initialized. Call initialize_database() first.")
104
+ error_msg = (
105
+ "Database not initialized. This usually means:\n"
106
+ "1. Missing or incorrect .env file in app/ directory\n"
107
+ "2. Database credentials are wrong\n"
108
+ "3. Database container is not running\n"
109
+ "4. Database initialization failed during startup\n"
110
+ "Please check the startup logs for more details."
111
+ )
112
+ logger.error(error_msg)
113
+ raise Exception(error_msg)
102
114
  return _connection_pool
103
115
 
104
116
 
105
- def get_sqlmodel_engine():
106
- """Get the SQLModel engine"""
107
- global _sqlmodel_engine
108
- if _sqlmodel_engine is None:
109
- raise Exception("Database not initialized. Call initialize_database() first.")
110
- return _sqlmodel_engine
111
-
112
-
113
117
  @contextmanager
114
118
  def get_db_connection():
115
119
  """Get a database connection from the pool (context manager)"""
@@ -217,5 +221,13 @@ class DatabaseManager:
217
221
  }
218
222
 
219
223
 
220
- # Database initialization is done lazily when needed
221
- # Call initialize_database() explicitly when you need to use the database
224
+ # Database initialization on module import
225
+ try:
226
+ initialize_database()
227
+ except Exception as e:
228
+ logger.error(f"Failed to initialize database on startup: {str(e)}")
229
+ logger.error("⚠️ CRITICAL: Application started without database connection!")
230
+ logger.error("⚠️ Please check your .env file and database configuration")
231
+ logger.error("⚠️ The application will not function properly without a database connection")
232
+ # Don't raise here to allow the app to start even if DB is unavailable
233
+ # But log it clearly so it's obvious what's wrong
@@ -0,0 +1,57 @@
1
+ import os
2
+ class Settings:
3
+
4
+ # Database URL
5
+ DATABASE_URL: str = os.getenv("DATABASE_URL")
6
+
7
+ DB_USER: str = os.getenv("DB_USER")
8
+ DB_HOST: str = os.getenv("DB_HOST")
9
+ DB_NAME: str = os.getenv("DB_NAME")
10
+ DB_PORT: str = os.getenv("DB_PORT")
11
+ DB_PASSWORD: str = os.getenv("DB_PASSWORD")
12
+
13
+ # Application settings
14
+ APP_NAME: str = os.getenv("APP_NAME", "Python Template API")
15
+ DEBUG: bool = os.getenv("DEBUG", "True").lower() in ("true",1)
16
+ APP_VERSION: str = os.getenv("APP_VERSION", "1.0.0")
17
+
18
+ # Logging settings
19
+ LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
20
+ LOG_FORMAT: str = os.getenv("LOG_FORMAT", "detailed") # detailed, json, simple
21
+ LOG_TO_FILE: bool = os.getenv("LOG_TO_FILE", "False").lower() in ("true", 1)
22
+ LOG_MAX_SIZE: int = int(os.getenv("LOG_MAX_SIZE", "10485760")) # 10MB
23
+ LOG_BACKUP_COUNT: int = int(os.getenv("LOG_BACKUP_COUNT", "5"))
24
+ LOG_DIR: str = os.getenv("LOG_DIR", "logs")
25
+
26
+ # Security settings
27
+ ENVIRONMENT: str = os.getenv("ENVIRONMENT")
28
+ ALGORITHM: str = os.getenv("ALGORITHM")
29
+ SECRET_KEY: str = os.getenv("SECRET_KEY")
30
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "120"))
31
+
32
+ # =============================================================================
33
+ # SHARED TABLES (main schema)
34
+ # =============================================================================
35
+ MAIN_TENANTS_TABLE = os.getenv("MAIN_TENANTS_TABLE")
36
+ MAIN_ROLE_PERMISSIONS_TABLE = os.getenv("MAIN_ROLE_PERMISSIONS_TABLE")
37
+ MAIN_USER_SUBSCRIPTIONS_TABLE = os.getenv("MAIN_USER_SUBSCRIPTIONS_TABLE")
38
+ MAIN_USER_SUBSCRIPTION_HISTORY_TABLE = os.getenv("MAIN_USER_SUBSCRIPTION_HISTORY_TABLE")
39
+ MAIN_SUBSCRIPTIONS_TABLE = os.getenv("MAIN_SUBSCRIPTIONS_TABLE")
40
+
41
+ # =============================================================================
42
+ # TENANT-SPECIFIC TABLES (tenant schemas)
43
+ # =============================================================================
44
+ TENANT_LOGIN_SETTINGS_TABLE = os.getenv("TENANT_LOGIN_SETTINGS_TABLE")
45
+ TENANT_ASSIGN_ROLES_TABLE = os.getenv("TENANT_ASSIGN_ROLES_TABLE")
46
+ TENANT_USER_GROUPS_TABLE = os.getenv("TENANT_USER_GROUPS_TABLE")
47
+
48
+ @property
49
+ def database_url(self) -> str:
50
+ if self.DATABASE_URL:
51
+ return self.DATABASE_URL
52
+
53
+ port = int(self.DB_PORT) if self.DB_PORT else 5432
54
+ return f"postgresql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{port}/{self.DB_NAME}"
55
+
56
+ # Global settings instance
57
+ db_settings = Settings()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trovesuite
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: TroveSuite services package providing authentication, authorization, notifications, 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
@@ -34,6 +34,8 @@ Requires-Dist: python-multipart>=0.0.6
34
34
  Requires-Dist: python-jose[cryptography]>=3.3.0
35
35
  Requires-Dist: passlib[bcrypt]>=1.7.4
36
36
  Requires-Dist: passlib[argon2]<2.0.0,>=1.7.4
37
+ Requires-Dist: uvicorn<0.39.0,>=0.38.0
38
+ Requires-Dist: pyjwt<3.0.0,>=2.10.1
37
39
  Provides-Extra: dev
38
40
  Requires-Dist: pytest>=8.4.2; extra == "dev"
39
41
  Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
@@ -6,6 +6,8 @@ python-multipart>=0.0.6
6
6
  python-jose[cryptography]>=3.3.0
7
7
  passlib[bcrypt]>=1.7.4
8
8
  passlib[argon2]<2.0.0,>=1.7.4
9
+ uvicorn<0.39.0,>=0.38.0
10
+ pyjwt<3.0.0,>=2.10.1
9
11
 
10
12
  [dev]
11
13
  pytest>=8.4.2
@@ -1,153 +0,0 @@
1
- import os
2
- import warnings
3
- from typing import Optional
4
-
5
- class Settings:
6
- """Settings configuration for TroveSuite Auth Service"""
7
-
8
- # =============================================================================
9
- # DATABASE CONFIGURATION
10
- # =============================================================================
11
- DATABASE_URL: str = os.getenv(
12
- "DATABASE_URL",
13
- "postgresql://username:password@localhost:5432/database_name"
14
- )
15
-
16
- # Alternative database configuration
17
- DB_USER: Optional[str] = os.getenv("DB_USER")
18
- DB_HOST: Optional[str] = os.getenv("DB_HOST")
19
- DB_NAME: Optional[str] = os.getenv("DB_NAME")
20
- DB_PORT: int = int(os.getenv("DB_PORT", "5432"))
21
- DB_PASSWORD: Optional[str] = os.getenv("DB_PASSWORD")
22
- ENVIRONMENT: str = os.getenv("ENVIRONMENT", "development")
23
-
24
- # =============================================================================
25
- # APPLICATION SETTINGS
26
- # =============================================================================
27
- APP_NAME: str = os.getenv("APP_NAME", "TroveSuite Auth Service")
28
- DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
29
-
30
- # =============================================================================
31
- # SECURITY SETTINGS
32
- # =============================================================================
33
- ALGORITHM: str = os.getenv("ALGORITHM", "HS256")
34
- SECRET_KEY: str = os.getenv("SECRET_KEY", "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7")
35
- ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "60"))
36
-
37
- # =============================================================================
38
- # LOGGING SETTINGS
39
- # =============================================================================
40
- LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
41
- LOG_FORMAT: str = os.getenv("LOG_FORMAT", "detailed") # detailed, json, simple
42
- LOG_TO_FILE: bool = os.getenv("LOG_TO_FILE", "False").lower() == "false"
43
- LOG_MAX_SIZE: int = int(os.getenv("LOG_MAX_SIZE", "10485760")) # 10MB
44
- LOG_BACKUP_COUNT: int = int(os.getenv("LOG_BACKUP_COUNT", "5"))
45
- LOG_DIR: str = os.getenv("LOG_DIR", "logs")
46
-
47
- # =============================================================================
48
- # DATABASE TABLE NAMES
49
- # =============================================================================
50
- # Main schema tables
51
- MAIN_TENANTS_TABLE: str = os.getenv("MAIN_TENANTS_TABLE", "tenants")
52
- ROLE_PERMISSIONS_TABLE: str = os.getenv("ROLE_PERMISSIONS_TABLE", "role_permissions")
53
-
54
- # Tenant-specific tables (used in queries with tenant schema)
55
- TENANT_LOGIN_SETTINGS_TABLE: str = os.getenv("TENANT_LOGIN_SETTINGS_TABLE", "login_settings")
56
- USER_GROUPS_TABLE: str = os.getenv("USER_GROUPS_TABLE", "user_groups")
57
- ASSIGN_ROLES_TABLE: str = os.getenv("ASSIGN_ROLES_TABLE", "assign_roles")
58
-
59
- # =============================================================================
60
- # AZURE CONFIGURATION (Optional - for queue functionality)
61
- # =============================================================================
62
- STORAGE_ACCOUNT_NAME: str = os.getenv("STORAGE_ACCOUNT_NAME", "")
63
- USER_ASSIGNED_MANAGED_IDENTITY: str = os.getenv("USER_ASSIGNED_MANAGED_IDENTITY", "")
64
-
65
- @property
66
- def database_url(self) -> str:
67
- """Get the database URL, either from DATABASE_URL or constructed from individual components"""
68
- if self.DATABASE_URL != "postgresql://username:password@localhost:5432/database_name":
69
- return self.DATABASE_URL
70
-
71
- # Validate individual components
72
- if not all([self.DB_USER, self.DB_HOST, self.DB_NAME, self.DB_PASSWORD]):
73
- missing = []
74
- if not self.DB_USER:
75
- missing.append("DB_USER")
76
- if not self.DB_HOST:
77
- missing.append("DB_HOST")
78
- if not self.DB_NAME:
79
- missing.append("DB_NAME")
80
- if not self.DB_PASSWORD:
81
- missing.append("DB_PASSWORD")
82
-
83
- raise ValueError(
84
- f"Database configuration incomplete. Missing environment variables: {', '.join(missing)}. "
85
- f"Please set these variables or provide a complete DATABASE_URL."
86
- )
87
-
88
- return f"postgresql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
89
-
90
- def validate_configuration(self) -> None:
91
- """Validate the current configuration and warn about potential issues"""
92
- warnings_list = []
93
-
94
- # Check for default secret key
95
- if self.SECRET_KEY == "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7":
96
- warnings_list.append(
97
- "SECRET_KEY is using the default value. This is insecure for production. "
98
- "Please set a strong, unique SECRET_KEY environment variable."
99
- )
100
-
101
- # Check for development environment in production-like settings
102
- if self.ENVIRONMENT == "development" and self.DEBUG is False:
103
- warnings_list.append(
104
- "ENVIRONMENT is set to 'development' but DEBUG is False. "
105
- "Consider setting ENVIRONMENT to 'production' for production deployments."
106
- )
107
-
108
- # Check database configuration
109
- try:
110
- self.database_url
111
- except ValueError as e:
112
- warnings_list.append(f"Database configuration issue: {str(e)}")
113
-
114
- # Check for missing Azure configuration if needed
115
- if self.ENVIRONMENT == "production" and not self.STORAGE_ACCOUNT_NAME:
116
- warnings_list.append(
117
- "STORAGE_ACCOUNT_NAME is not set. Azure queue functionality may not work properly."
118
- )
119
-
120
- # Emit warnings
121
- for warning in warnings_list:
122
- warnings.warn(warning, UserWarning)
123
-
124
- def get_configuration_summary(self) -> dict:
125
- """Get a summary of the current configuration (excluding sensitive data)"""
126
- return {
127
- "app_name": self.APP_NAME,
128
- "environment": self.ENVIRONMENT,
129
- "debug": self.DEBUG,
130
- "database_host": self.DB_HOST,
131
- "database_port": self.DB_PORT,
132
- "database_name": self.DB_NAME,
133
- "database_user": self.DB_USER,
134
- "log_level": self.LOG_LEVEL,
135
- "log_format": self.LOG_FORMAT,
136
- "log_to_file": self.LOG_TO_FILE,
137
- "algorithm": self.ALGORITHM,
138
- "access_token_expire_minutes": self.ACCESS_TOKEN_EXPIRE_MINUTES,
139
- "MAIN_TENANTS_TABLE": self.MAIN_TENANTS_TABLE,
140
- "role_permissions_table": self.ROLE_PERMISSIONS_TABLE,
141
- "TENANT_LOGIN_SETTINGS_TABLE": self.TENANT_LOGIN_SETTINGS_TABLE,
142
- "user_groups_table": self.USER_GROUPS_TABLE,
143
- "assign_roles_table": self.ASSIGN_ROLES_TABLE,
144
- }
145
-
146
- # Global settings instance
147
- db_settings = Settings()
148
-
149
- # Validate configuration on import
150
- try:
151
- db_settings.validate_configuration()
152
- except Exception as e:
153
- warnings.warn("Configuration validation failed: %s", str(e), UserWarning)
File without changes
File without changes
File without changes
File without changes
File without changes