You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
orquestrador/admin_app/api/routes/tools.py

220 lines
7.6 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from admin_app.api.dependencies import get_current_staff_principal, get_settings, require_admin_permission
from admin_app.api.schemas import (
AdminToolContractsResponse,
AdminToolDraftIntakeRequest,
AdminToolDraftIntakeResponse,
AdminToolDraftListResponse,
AdminToolManagementActionResponse,
AdminToolOverviewResponse,
AdminToolPublicationListResponse,
AdminToolReviewQueueResponse,
)
from admin_app.core import AdminSettings, AuthenticatedStaffPrincipal
from admin_app.services import ToolManagementService
from shared.contracts import AdminPermission
router = APIRouter(prefix="/tools", tags=["tools"])
def _build_service(settings: AdminSettings) -> ToolManagementService:
return ToolManagementService(settings)
@router.get(
"/overview",
response_model=AdminToolOverviewResponse,
)
def tools_overview(
settings: AdminSettings = Depends(get_settings),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS)
),
):
service = _build_service(settings)
payload = service.build_overview_payload()
return AdminToolOverviewResponse(
service="orquestrador-admin",
mode=payload["mode"],
metrics=payload["metrics"],
workflow=payload["workflow"],
actions=_build_actions(settings),
next_steps=payload["next_steps"],
)
@router.get(
"/contracts",
response_model=AdminToolContractsResponse,
)
def tool_contracts(
settings: AdminSettings = Depends(get_settings),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS)
),
):
service = _build_service(settings)
payload = service.build_contracts_payload()
return AdminToolContractsResponse(
service="orquestrador-admin",
publication_source_service=payload["publication_source_service"],
publication_target_service=payload["publication_target_service"],
lifecycle_statuses=payload["lifecycle_statuses"],
parameter_types=payload["parameter_types"],
publication_fields=payload["publication_fields"],
published_tool_fields=payload["published_tool_fields"],
)
@router.get(
"/drafts",
response_model=AdminToolDraftListResponse,
)
def tool_drafts(
settings: AdminSettings = Depends(get_settings),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS)
),
):
service = _build_service(settings)
payload = service.build_drafts_payload()
return AdminToolDraftListResponse(
service="orquestrador-admin",
storage_status=payload["storage_status"],
message=payload["message"],
drafts=payload["drafts"],
supported_statuses=payload["supported_statuses"],
)
@router.post(
"/drafts/intake",
response_model=AdminToolDraftIntakeResponse,
)
def tool_draft_intake(
draft: AdminToolDraftIntakeRequest,
settings: AdminSettings = Depends(get_settings),
current_staff: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_TOOL_DRAFTS)
),
):
service = _build_service(settings)
try:
payload = service.preview_draft_submission(
draft.model_dump(),
owner_name=current_staff.display_name,
)
except ValueError as exc:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
detail=str(exc),
) from exc
return AdminToolDraftIntakeResponse(
service="orquestrador-admin",
storage_status=payload["storage_status"],
message=payload["message"],
draft_preview=payload["draft_preview"],
warnings=payload["warnings"],
next_steps=payload["next_steps"],
)
@router.get(
"/review-queue",
response_model=AdminToolReviewQueueResponse,
)
def tool_review_queue(
settings: AdminSettings = Depends(get_settings),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.REVIEW_TOOL_GENERATIONS)
),
):
service = _build_service(settings)
payload = service.build_review_queue_payload()
return AdminToolReviewQueueResponse(
service="orquestrador-admin",
queue_mode=payload["queue_mode"],
message=payload["message"],
items=payload["items"],
supported_statuses=payload["supported_statuses"],
)
@router.get(
"/publications",
response_model=AdminToolPublicationListResponse,
)
def tool_publications(
settings: AdminSettings = Depends(get_settings),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.PUBLISH_TOOLS)
),
):
service = _build_service(settings)
payload = service.build_publications_payload()
return AdminToolPublicationListResponse(
service="orquestrador-admin",
source=payload["source"],
target_service=payload["target_service"],
publications=payload["publications"],
)
def _build_actions(settings: AdminSettings) -> list[AdminToolManagementActionResponse]:
return [
AdminToolManagementActionResponse(
key="overview",
label="Overview de tools",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/overview"),
required_permission=AdminPermission.MANAGE_TOOL_DRAFTS,
description="Snapshot inicial da governanca de tools no admin.",
),
AdminToolManagementActionResponse(
key="contracts",
label="Contratos compartilhados",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/contracts"),
required_permission=AdminPermission.MANAGE_TOOL_DRAFTS,
description="Enumera lifecycle, tipos de parametro e campos de publicacao.",
),
AdminToolManagementActionResponse(
key="drafts",
label="Fila de drafts",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/drafts"),
required_permission=AdminPermission.MANAGE_TOOL_DRAFTS,
description="Base do cadastro de novas tools e estados vazios da fase atual.",
),
AdminToolManagementActionResponse(
key="draft_intake",
label="Pre-cadastro de tool",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/drafts/intake"),
required_permission=AdminPermission.MANAGE_TOOL_DRAFTS,
description="Valida o formulario real de cadastro antes da persistencia definitiva.",
),
AdminToolManagementActionResponse(
key="review_queue",
label="Fila de revisao",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/review-queue"),
required_permission=AdminPermission.REVIEW_TOOL_GENERATIONS,
description="Superficie para validacao, revisao tecnica e aprovacao humana.",
),
AdminToolManagementActionResponse(
key="publications",
label="Catalogo de publicacoes",
href=_build_prefixed_path(settings.admin_api_prefix, "/tools/publications"),
required_permission=AdminPermission.PUBLISH_TOOLS,
description="Catalogo bootstrap de tools ativas voltadas ao runtime de produto.",
),
]
def _build_prefixed_path(api_prefix: str, path: str) -> str:
normalized_prefix = api_prefix.rstrip("/")
normalized_path = path if path.startswith("/") else f"/{path}"
if not normalized_prefix:
return normalized_path
if normalized_path == "/":
return f"{normalized_prefix}/"
return f"{normalized_prefix}{normalized_path}"