2025-07-17 19:46:41 +02:00
|
|
|
"""
|
2025-07-20 23:43:42 +02:00
|
|
|
Tenant routes for gateway - FIXED VERSION
|
2025-07-17 19:46:41 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
2025-07-20 23:15:57 +02:00
|
|
|
@router.post("/register")
|
2025-07-17 19:46:41 +02:00
|
|
|
async def create_tenant(request: Request):
|
|
|
|
|
"""Proxy tenant creation to tenant service"""
|
|
|
|
|
try:
|
|
|
|
|
body = await request.body()
|
2025-07-20 23:43:42 +02:00
|
|
|
|
|
|
|
|
# ✅ 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)
|
2025-07-17 19:46:41 +02:00
|
|
|
|
|
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
|
|
response = await client.post(
|
2025-07-20 23:15:57 +02:00
|
|
|
f"{settings.TENANT_SERVICE_URL}/api/v1/tenants/register",
|
2025-07-17 19:46:41 +02:00
|
|
|
content=body,
|
2025-07-20 23:43:42 +02:00
|
|
|
headers=headers
|
2025-07-17 19:46:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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:
|
2025-07-20 23:43:42 +02:00
|
|
|
# ✅ 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)
|
2025-07-17 19:46:41 +02:00
|
|
|
|
|
|
|
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
|
|
|
response = await client.get(
|
2025-07-20 23:43:42 +02:00
|
|
|
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)
|
2025-07-17 19:46:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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"
|
|
|
|
|
)
|