154 lines
5.3 KiB
Python
154 lines
5.3 KiB
Python
"""
|
|
Tenant API - ATOMIC operations
|
|
Handles basic CRUD operations for tenants
|
|
"""
|
|
|
|
import structlog
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Path
|
|
from typing import Dict, Any
|
|
from uuid import UUID
|
|
|
|
from app.schemas.tenants import TenantResponse, TenantUpdate
|
|
from app.services.tenant_service import EnhancedTenantService
|
|
from shared.auth.decorators import get_current_user_dep
|
|
from shared.auth.access_control import admin_role_required
|
|
from shared.routing.route_builder import RouteBuilder
|
|
from shared.database.base import create_database_manager
|
|
from shared.monitoring.metrics import track_endpoint_metrics
|
|
|
|
logger = structlog.get_logger()
|
|
router = APIRouter()
|
|
route_builder = RouteBuilder("tenants")
|
|
|
|
# Dependency injection for enhanced tenant service
|
|
def get_enhanced_tenant_service():
|
|
try:
|
|
from app.core.config import settings
|
|
database_manager = create_database_manager(settings.DATABASE_URL, "tenant-service")
|
|
return EnhancedTenantService(database_manager)
|
|
except Exception as e:
|
|
logger.error("Failed to create enhanced tenant service", error=str(e))
|
|
raise HTTPException(status_code=500, detail="Service initialization failed")
|
|
|
|
@router.get(route_builder.build_base_route("{tenant_id}", include_tenant_prefix=False), response_model=TenantResponse)
|
|
@track_endpoint_metrics("tenant_get")
|
|
async def get_tenant(
|
|
tenant_id: UUID = Path(..., description="Tenant ID"),
|
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
|
tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
|
|
):
|
|
"""Get tenant by ID - ATOMIC operation - ENHANCED with logging"""
|
|
|
|
logger.info(
|
|
"Tenant GET request received",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id"),
|
|
user_type=current_user.get("type", "user"),
|
|
is_service=current_user.get("type") == "service",
|
|
role=current_user.get("role"),
|
|
service_name=current_user.get("service", "none")
|
|
)
|
|
|
|
tenant = await tenant_service.get_tenant_by_id(str(tenant_id))
|
|
if not tenant:
|
|
logger.warning(
|
|
"Tenant not found",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id")
|
|
)
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Tenant not found"
|
|
)
|
|
|
|
logger.debug(
|
|
"Tenant GET request successful",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id")
|
|
)
|
|
|
|
return tenant
|
|
|
|
@router.put(route_builder.build_base_route("{tenant_id}", include_tenant_prefix=False), response_model=TenantResponse)
|
|
@admin_role_required
|
|
async def update_tenant(
|
|
update_data: TenantUpdate,
|
|
tenant_id: UUID = Path(..., description="Tenant ID"),
|
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
|
tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
|
|
):
|
|
"""Update tenant information - ATOMIC operation (Admin+ only)"""
|
|
|
|
try:
|
|
result = await tenant_service.update_tenant(
|
|
str(tenant_id),
|
|
update_data,
|
|
current_user["user_id"]
|
|
)
|
|
return result
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error("Tenant update failed",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user["user_id"],
|
|
error=str(e))
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Tenant update failed"
|
|
)
|
|
|
|
@router.delete(route_builder.build_base_route("{tenant_id}", include_tenant_prefix=False))
|
|
@track_endpoint_metrics("tenant_delete")
|
|
async def delete_tenant(
|
|
tenant_id: UUID = Path(..., description="Tenant ID"),
|
|
current_user: Dict[str, Any] = Depends(get_current_user_dep),
|
|
tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
|
|
):
|
|
"""Delete tenant and all associated data - ATOMIC operation (Owner/Admin or System only)"""
|
|
|
|
logger.info(
|
|
"Tenant DELETE request received",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id"),
|
|
user_type=current_user.get("type", "user"),
|
|
is_service=current_user.get("type") == "service",
|
|
role=current_user.get("role"),
|
|
service_name=current_user.get("service", "none")
|
|
)
|
|
|
|
try:
|
|
# Allow internal service calls to bypass admin check
|
|
skip_admin_check = current_user.get("type") == "service"
|
|
|
|
result = await tenant_service.delete_tenant(
|
|
str(tenant_id),
|
|
requesting_user_id=current_user.get("user_id"),
|
|
skip_admin_check=skip_admin_check
|
|
)
|
|
|
|
logger.info(
|
|
"Tenant DELETE request successful",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id"),
|
|
deleted_items=result.get("deleted_items")
|
|
)
|
|
|
|
return {
|
|
"message": "Tenant deleted successfully",
|
|
"summary": result
|
|
}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error("Tenant deletion failed",
|
|
tenant_id=str(tenant_id),
|
|
user_id=current_user.get("user_id"),
|
|
error=str(e))
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Tenant deletion failed"
|
|
)
|