79 lines
3.7 KiB
Python
79 lines
3.7 KiB
Python
from fastapi import Request, status, HTTPException
|
|
from fastapi.responses import JSONResponse
|
|
from webapi.middleware.freeleaps_auth_middleware import request_context_var
|
|
from common.log.module_logger import ModuleLogger
|
|
|
|
|
|
class DatabaseMiddleware:
|
|
def __init__(self, app):
|
|
self.app = app
|
|
self.module_logger = ModuleLogger(sender_id=DatabaseMiddleware)
|
|
|
|
async def __call__(self, scope, receive, send):
|
|
if scope["type"] != "http":
|
|
return await self.app(scope, receive, send)
|
|
|
|
request = Request(scope, receive)
|
|
|
|
# Get tenant id from auth context (set by FreeleapsAuthMiddleware)
|
|
product_id = None
|
|
try:
|
|
ctx = request_context_var.get()
|
|
product_id = getattr(ctx, "product_id", None)
|
|
await self.module_logger.log_info(f"Retrieved product_id from auth context: {product_id}")
|
|
except Exception as e:
|
|
await self.module_logger.log_error(f"Failed to get auth context: {str(e)}")
|
|
product_id = None
|
|
|
|
# Get tenant cache and main database from app state
|
|
try:
|
|
tenant_cache = request.app.state.tenant_cache
|
|
main_db = request.app.state.main_db
|
|
await self.module_logger.log_info(f"Retrieved app state - tenant_cache: {'success' if tenant_cache is not None else 'fail'}, main_db: {'success' if main_db is not None else 'fail'}")
|
|
except Exception as e:
|
|
await self.module_logger.log_error(f"Failed to get app state: {str(e)}")
|
|
response = JSONResponse(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
content={"detail": "Database not properly initialized"}
|
|
)
|
|
return await response(scope, receive, send)
|
|
|
|
if not product_id:
|
|
# Compatibility / public routes: use main database with tenant models initialized
|
|
await self.module_logger.log_info(f"No product_id - using main database for path: {request.url.path}")
|
|
|
|
# Get main database with Beanie initialized for tenant models
|
|
main_db_initialized = await tenant_cache.get_main_db_initialized()
|
|
|
|
request.state.db = main_db_initialized
|
|
request.state.product_id = None
|
|
await self.module_logger.log_info(f"Successfully initialized main database with tenant models")
|
|
return await self.app(scope, receive, send)
|
|
|
|
try:
|
|
# Get tenant-specific database with Beanie already initialized (cached)
|
|
await self.module_logger.log_info(f"Attempting to get tenant database for product_id: {product_id}")
|
|
tenant_db = await tenant_cache.get_initialized_db(product_id)
|
|
|
|
request.state.db = tenant_db
|
|
request.state.product_id = product_id
|
|
await self.module_logger.log_info(f"Successfully retrieved cached tenant database with Beanie for product_id: {product_id}")
|
|
|
|
except HTTPException as e:
|
|
# Handle tenant not found or inactive (HTTPException from TenantDBCache)
|
|
await self.module_logger.log_error(f"Tenant error for {product_id}: [{e.status_code}] {e.detail}")
|
|
response = JSONResponse(
|
|
status_code=e.status_code,
|
|
content={"detail": e.detail}
|
|
)
|
|
return await response(scope, receive, send)
|
|
|
|
except Exception as e:
|
|
await self.module_logger.log_error(f"Database error for tenant {product_id}: {str(e)}")
|
|
response = JSONResponse(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
content={"detail": "Database connection error"}
|
|
)
|
|
return await response(scope, receive, send)
|
|
|
|
return await self.app(scope, receive, send) |