251dd703ed
Migration 035: tenants table with 'Schaeffler' default seed. Migration 036: tenant_id FK on all tables, RLS policies, backfill. New domains/tenants/ with CRUD router (admin only). All domain models extended with tenant_id FK. core/database.py: get_db_for_tenant with RLS context setter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
import uuid
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database import get_db
|
|
from app.utils.auth import require_admin
|
|
from app.domains.tenants.schemas import TenantCreate, TenantUpdate, TenantOut
|
|
from app.domains.tenants import service
|
|
|
|
router = APIRouter(prefix="/tenants", tags=["tenants"])
|
|
|
|
|
|
@router.get("/", response_model=list[TenantOut])
|
|
async def list_tenants(
|
|
db: AsyncSession = Depends(get_db),
|
|
_: object = Depends(require_admin),
|
|
):
|
|
rows = await service.list_tenants(db)
|
|
result = []
|
|
for row in rows:
|
|
tenant = row["tenant"]
|
|
out = TenantOut.model_validate(tenant)
|
|
out.user_count = row["user_count"]
|
|
result.append(out)
|
|
return result
|
|
|
|
|
|
@router.get("/{tenant_id}", response_model=TenantOut)
|
|
async def get_tenant(
|
|
tenant_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: object = Depends(require_admin),
|
|
):
|
|
tenant = await service.get_tenant(db, tenant_id)
|
|
if not tenant:
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Tenant not found")
|
|
return TenantOut.model_validate(tenant)
|
|
|
|
|
|
@router.post("/", response_model=TenantOut, status_code=status.HTTP_201_CREATED)
|
|
async def create_tenant(
|
|
body: TenantCreate,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: object = Depends(require_admin),
|
|
):
|
|
tenant = await service.create_tenant(db, name=body.name, slug=body.slug, is_active=body.is_active)
|
|
return TenantOut.model_validate(tenant)
|
|
|
|
|
|
@router.put("/{tenant_id}", response_model=TenantOut)
|
|
async def update_tenant(
|
|
tenant_id: uuid.UUID,
|
|
body: TenantUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: object = Depends(require_admin),
|
|
):
|
|
tenant = await service.update_tenant(
|
|
db, tenant_id,
|
|
name=body.name,
|
|
slug=body.slug,
|
|
is_active=body.is_active,
|
|
)
|
|
if not tenant:
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Tenant not found")
|
|
return TenantOut.model_validate(tenant)
|
|
|
|
|
|
@router.delete("/{tenant_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_tenant(
|
|
tenant_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db),
|
|
_: object = Depends(require_admin),
|
|
):
|
|
ok = await service.delete_tenant(db, tenant_id)
|
|
if not ok:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Tenant not found or still has users assigned",
|
|
)
|