# services/tenant/app/api/tenants.py """ Tenant API endpoints """ from fastapi import APIRouter, Depends, HTTPException, status, Request from sqlalchemy.ext.asyncio import AsyncSession from typing import List import structlog from app.core.database import get_db from app.schemas.tenants import ( BakeryRegistration, TenantResponse, TenantAccessResponse, TenantUpdate, TenantMemberResponse ) from app.services.tenant_service import TenantService # Import unified authentication from shared.auth.decorators import ( get_current_user_dep, get_current_tenant_id_dep, require_role ) logger = structlog.get_logger() router = APIRouter() @router.post("/tenants/register", response_model=TenantResponse) async def register_bakery( bakery_data: BakeryRegistration, current_user: Dict[str, Any] = Depends(get_current_user_dep), db: AsyncSession = Depends(get_db) ): try: result = await TenantService.create_bakery(bakery_data, current_user["user_id"], db) logger.info(f"Bakery registered: {bakery_data.name} by {current_user['email']}") return result except Exception as e: logger.error(f"Bakery registration failed: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Bakery registration failed" ) @router.get("/tenants/{tenant_id}/access/{user_id}", response_model=TenantAccessResponse) async def verify_tenant_access( tenant_id: str, user_id: str, db: AsyncSession = Depends(get_db) ): """Verify if user has access to tenant - Called by Gateway""" try: access_info = await TenantService.verify_user_access(user_id, tenant_id, db) return access_info except Exception as e: logger.error(f"Access verification failed: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Access verification failed" ) @router.get("/users/{user_id}/tenants", response_model=List[TenantResponse]) @require_authentication async def get_user_tenants( user_id: str, current_user: Dict[str, Any] = Depends(get_current_user_dep), db: AsyncSession = Depends(get_db) ): # Users can only see their own tenants if current_user["user_id"] != user_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied" ) try: tenants = await TenantService.get_user_tenants(user_id, db) return tenants except Exception as e: logger.error(f"Failed to get user tenants: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to retrieve tenants" ) @router.get("/tenants/{tenant_id}", response_model=TenantResponse) @require_authentication async def get_tenant( tenant_id: str, current_user: Dict[str, Any] = Depends(get_current_user_dep), db: AsyncSession = Depends(get_db) ): # Verify user has access to tenant access = await TenantService.verify_user_access(current_user["user_id"], tenant_id, db) if not access.has_access: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied to tenant" ) tenant = await TenantService.get_tenant_by_id(tenant_id, db) if not tenant: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Tenant not found" ) return tenant @router.put("/tenants/{tenant_id}", response_model=TenantResponse) @require_authentication async def update_tenant( tenant_id: str, update_data: TenantUpdate, current_user: Dict[str, Any] = Depends(get_current_user_dep), db: AsyncSession = Depends(get_db) ): try: result = await TenantService.update_tenant(tenant_id, update_data, current_user["user_id"], db) return result except HTTPException: raise except Exception as e: logger.error(f"Tenant update failed: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Tenant update failed" ) @router.post("/tenants/{tenant_id}/members", response_model=TenantMemberResponse) @require_authentication async def add_team_member( tenant_id: str, user_id: str, role: str, current_user: Dict[str, Any] = Depends(get_current_user_dep), db: AsyncSession = Depends(get_db) ): try: result = await TenantService.add_team_member( tenant_id, user_id, role, current_user["user_id"], db ) return result except HTTPException: raise except Exception as e: logger.error(f"Add team member failed: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to add team member" )