""" Tenant routes for gateway - FIXED VERSION """ from fastapi import APIRouter, Request, HTTPException from fastapi.responses import JSONResponse import httpx import logging from app.core.config import settings logger = logging.getLogger(__name__) router = APIRouter() @router.post("/register") async def create_tenant(request: Request): """Proxy tenant creation to tenant service""" try: body = await request.body() # ✅ FIX: Forward all headers AND add user context from gateway auth headers = dict(request.headers) headers.pop("host", None) # Remove host header # ✅ ADD USER CONTEXT FROM GATEWAY AUTHENTICATION # Gateway middleware already verified the token and added user to request.state if hasattr(request.state, 'user'): headers["X-User-ID"] = str(request.state.user.get("user_id")) headers["X-User-Email"] = request.state.user.get("email", "") headers["X-User-Role"] = request.state.user.get("role", "user") # Add tenant ID if it exists if hasattr(request.state, 'tenant_id') and request.state.tenant_id: headers["X-Tenant-ID"] = str(request.state.tenant_id) elif request.state.user.get("tenant_id"): headers["X-Tenant-ID"] = str(request.state.user.get("tenant_id")) roles = request.state.user.get("roles", []) if roles: headers["X-User-Roles"] = ",".join(roles) permissions = request.state.user.get("permissions", []) if permissions: headers["X-User-Permissions"] = ",".join(permissions) async with httpx.AsyncClient(timeout=10.0) as client: response = await client.post( f"{settings.TENANT_SERVICE_URL}/api/v1/tenants/register", content=body, headers=headers ) return JSONResponse( status_code=response.status_code, content=response.json() ) except httpx.RequestError as e: logger.error(f"Tenant service unavailable: {e}") raise HTTPException( status_code=503, detail="Tenant service unavailable" ) @router.get("/") async def get_tenants(request: Request): """Get tenants""" try: # ✅ FIX: Same pattern for GET requests headers = dict(request.headers) headers.pop("host", None) # Add user context from gateway auth if hasattr(request.state, 'user'): headers["X-User-ID"] = str(request.state.user.get("user_id")) headers["X-User-Email"] = request.state.user.get("email", "") headers["X-User-Role"] = request.state.user.get("role", "user") if hasattr(request.state, 'tenant_id') and request.state.tenant_id: headers["X-Tenant-ID"] = str(request.state.tenant_id) elif request.state.user.get("tenant_id"): headers["X-Tenant-ID"] = str(request.state.user.get("tenant_id")) roles = request.state.user.get("roles", []) if roles: headers["X-User-Roles"] = ",".join(roles) async with httpx.AsyncClient(timeout=10.0) as client: response = await client.get( f"{settings.TENANT_SERVICE_URL}/api/v1/tenants", headers=headers ) return JSONResponse( status_code=response.status_code, content=response.json() ) except httpx.RequestError as e: logger.error(f"Tenant service unavailable: {e}") raise HTTPException( status_code=503, detail="Tenant service unavailable" ) # ✅ ADD: Generic proxy function like the data service has async def _proxy_tenant_request(request: Request, target_path: str, method: str = None): """Proxy request to tenant service with user context""" try: url = f"{settings.TENANT_SERVICE_URL}{target_path}" # Forward headers with user context headers = dict(request.headers) headers.pop("host", None) # Add user context from gateway authentication if hasattr(request.state, 'user'): headers["X-User-ID"] = str(request.state.user.get("user_id")) headers["X-User-Email"] = request.state.user.get("email", "") headers["X-User-Role"] = request.state.user.get("role", "user") if hasattr(request.state, 'tenant_id') and request.state.tenant_id: headers["X-Tenant-ID"] = str(request.state.tenant_id) elif request.state.user.get("tenant_id"): headers["X-Tenant-ID"] = str(request.state.user.get("tenant_id")) roles = request.state.user.get("roles", []) if roles: headers["X-User-Roles"] = ",".join(roles) # Get request body if present body = None request_method = method or request.method if request_method in ["POST", "PUT", "PATCH"]: body = await request.body() async with httpx.AsyncClient(timeout=30.0) as client: response = await client.request( method=request_method, url=url, headers=headers, content=body, params=dict(request.query_params) ) return JSONResponse( status_code=response.status_code, content=response.json() ) except httpx.RequestError as e: logger.error(f"Tenant service unavailable: {e}") raise HTTPException( status_code=503, detail="Tenant service unavailable" )