Subir todos los cambios recientes a la rama principal
This commit is contained in:
@@ -8,10 +8,20 @@ from fastapi import Request, HTTPException, status
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.responses import Response
|
||||
import structlog
|
||||
from contextlib import asynccontextmanager
|
||||
from sqlalchemy.sql import text
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
# Correct the usage of async for by wrapping it in an async function
|
||||
@asynccontextmanager
|
||||
async def get_db_context():
|
||||
from app.core.database import get_db
|
||||
async for db in get_db():
|
||||
yield db
|
||||
|
||||
|
||||
class TenantMiddleware(BaseHTTPMiddleware):
|
||||
"""
|
||||
Middleware para extraer y validar información del tenant.
|
||||
@@ -34,33 +44,56 @@ class TenantMiddleware(BaseHTTPMiddleware):
|
||||
"""Process request and add tenant information."""
|
||||
|
||||
# Skip tenant validation for excluded paths
|
||||
if request.url.path in self.EXCLUDED_PATHS or request.url.path.startswith("/docs"):
|
||||
if request.url.path in self.EXCLUDED_PATHS or any(request.url.path.startswith(path) for path in self.EXCLUDED_PATHS):
|
||||
return await call_next(request)
|
||||
|
||||
# Extract tenant from header
|
||||
tenant_id = request.headers.get("X-Tenant-ID")
|
||||
tenant_slug = request.headers.get("X-Tenant-Slug")
|
||||
|
||||
# For now, we'll be more permissive in development
|
||||
# In production, tenant should be strictly required
|
||||
# Revertir cambios para requerir encabezados de tenant
|
||||
if not tenant_id and not tenant_slug:
|
||||
logger.warning(
|
||||
"Request without tenant information",
|
||||
path=request.url.path,
|
||||
method=request.method
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Tenant information required (X-Tenant-ID or X-Tenant-Slug header)"
|
||||
)
|
||||
# For now, continue without tenant for development
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_400_BAD_REQUEST,
|
||||
# detail="Tenant information required (X-Tenant-ID or X-Tenant-Slug header)"
|
||||
# )
|
||||
|
||||
# Store tenant info in request state
|
||||
request.state.tenant_id = tenant_id
|
||||
request.state.tenant_slug = tenant_slug
|
||||
|
||||
# TODO: Validate tenant exists and is active
|
||||
# This would involve a database query which we'll implement later
|
||||
# Validate tenant exists and is active
|
||||
if tenant_id or tenant_slug:
|
||||
from app.core.database import get_db
|
||||
from app.models.tenant import Tenant
|
||||
|
||||
# Update the middleware to use the new context manager
|
||||
async with get_db_context() as db:
|
||||
tenant = await db.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT * FROM tenants
|
||||
WHERE id = :tenant_id OR slug = :tenant_slug AND status = 'active'
|
||||
"""
|
||||
),
|
||||
{"tenant_id": tenant_id, "tenant_slug": tenant_slug}
|
||||
)
|
||||
tenant = tenant.fetchone()
|
||||
|
||||
if not tenant:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Tenant not found or inactive"
|
||||
)
|
||||
|
||||
# Store validated tenant info
|
||||
request.state.tenant = tenant
|
||||
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Tenant information required (X-Tenant-ID or X-Tenant-Slug header)"
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
"Tenant middleware processed",
|
||||
|
||||
Reference in New Issue
Block a user