2026-08-03 09:34:08 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, Body, Request
|
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
from app.api.v1.endpoints.platform import ok, fail
|
|
|
|
|
from app.db.platform_store import get_platform_store
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/tenants", tags=["tenant"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _actor(request: Request) -> str | None:
|
|
|
|
|
auth = request.headers.get("Authorization", "")
|
|
|
|
|
token = auth.replace("Bearer ", "").strip()
|
|
|
|
|
return token or None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("")
|
|
|
|
|
def list_tenants() -> dict[str, Any]:
|
|
|
|
|
return ok(get_platform_store().tenants())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("")
|
|
|
|
|
def create_tenant(payload: dict[str, Any] = Body(...), request: Request = None) -> dict[str, Any]:
|
|
|
|
|
store = get_platform_store()
|
|
|
|
|
try:
|
|
|
|
|
tenant = store.create_tenant(payload)
|
|
|
|
|
except KeyError as e:
|
|
|
|
|
raise fail(400, f"missing field: {e}")
|
|
|
|
|
store.record_audit(
|
|
|
|
|
action="tenant.create",
|
|
|
|
|
actor_id=_actor(request) if request else None,
|
|
|
|
|
target_type="tenant",
|
|
|
|
|
target_id=tenant["id"],
|
|
|
|
|
tenant_id=tenant["id"],
|
|
|
|
|
detail=f"name={tenant.get('name')}",
|
|
|
|
|
)
|
|
|
|
|
return ok(tenant)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{tenant_id}")
|
|
|
|
|
def get_tenant(tenant_id: str) -> dict[str, Any]:
|
|
|
|
|
try:
|
|
|
|
|
return ok(get_platform_store().tenant(tenant_id))
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise fail(404, "tenant not found")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/{tenant_id}")
|
|
|
|
|
def update_tenant(tenant_id: str, payload: dict[str, Any] = Body(...), request: Request = None) -> dict[str, Any]:
|
|
|
|
|
store = get_platform_store()
|
|
|
|
|
try:
|
|
|
|
|
tenant = store.update_tenant(tenant_id, payload)
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise fail(404, "tenant not found")
|
|
|
|
|
store.record_audit(
|
|
|
|
|
action="tenant.update",
|
|
|
|
|
actor_id=_actor(request) if request else None,
|
|
|
|
|
target_type="tenant",
|
|
|
|
|
target_id=tenant_id,
|
|
|
|
|
tenant_id=tenant_id,
|
|
|
|
|
detail=f"fields={','.join(payload.keys())}",
|
|
|
|
|
)
|
|
|
|
|
return ok(tenant)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/{tenant_id}/quota")
|
|
|
|
|
def set_quota(tenant_id: str, payload: dict[str, Any] = Body(...), request: Request = None) -> dict[str, Any]:
|
|
|
|
|
store = get_platform_store()
|
|
|
|
|
try:
|
2026-08-17 09:15:36 +08:00
|
|
|
tenant = store.set_tenant_quota(tenant_id, payload)
|
2026-08-03 09:34:08 +08:00
|
|
|
except KeyError:
|
|
|
|
|
raise fail(404, "tenant not found")
|
|
|
|
|
store.record_audit(
|
|
|
|
|
action="tenant.quota.set",
|
|
|
|
|
actor_id=_actor(request) if request else None,
|
|
|
|
|
target_type="tenant",
|
|
|
|
|
target_id=tenant_id,
|
|
|
|
|
tenant_id=tenant_id,
|
|
|
|
|
)
|
|
|
|
|
return ok(tenant)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/{tenant_id}/retention-policy")
|
|
|
|
|
def set_retention(tenant_id: str, payload: dict[str, Any] = Body(...), request: Request = None) -> dict[str, Any]:
|
|
|
|
|
store = get_platform_store()
|
|
|
|
|
try:
|
|
|
|
|
tenant = store.set_tenant_retention(tenant_id, payload.get("retention_policy_id"))
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise fail(404, "tenant not found")
|
|
|
|
|
store.record_audit(
|
|
|
|
|
action="tenant.retention.set",
|
|
|
|
|
actor_id=_actor(request) if request else None,
|
|
|
|
|
target_type="tenant",
|
|
|
|
|
target_id=tenant_id,
|
|
|
|
|
tenant_id=tenant_id,
|
|
|
|
|
)
|
|
|
|
|
return ok(tenant)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.delete("/{tenant_id}")
|
|
|
|
|
def delete_tenant(tenant_id: str, request: Request = None) -> dict[str, Any]:
|
|
|
|
|
store = get_platform_store()
|
|
|
|
|
try:
|
|
|
|
|
tenant = store.delete_tenant(tenant_id)
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise fail(404, "tenant not found")
|
|
|
|
|
store.record_audit(
|
|
|
|
|
action="tenant.delete",
|
|
|
|
|
actor_id=_actor(request) if request else None,
|
|
|
|
|
target_type="tenant",
|
|
|
|
|
target_id=tenant_id,
|
|
|
|
|
tenant_id=tenant_id,
|
|
|
|
|
detail=f"name={tenant.get('name')}",
|
|
|
|
|
)
|
|
|
|
|
return ok(tenant)
|