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/system.py

309 lines
10 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import RedirectResponse, Response
from admin_app.api.dependencies import (
get_current_staff_permissions,
get_security_service,
get_settings,
require_admin_permission,
)
from admin_app.api.panel_session import (
PANEL_ACCESS_COOKIE_NAME,
PANEL_COOKIE_SAMESITE,
PANEL_REFRESH_COOKIE_NAME,
build_panel_cookie_path,
should_use_secure_cookies,
)
from admin_app.api.schemas import (
AdminCapabilityResponse,
AdminCurrentAccessResponse,
AdminHealthResponse,
AdminSystemBotGovernedConfigurationResponse,
AdminSystemConfigurationResponse,
AdminSystemFunctionalConfigurationCatalogResponse,
AdminSystemFunctionalConfigurationDetailResponse,
AdminSystemInfoResponse,
AdminSystemModelRuntimeSeparationResponse,
AdminSystemRuntimeConfigurationResponse,
AdminSystemSecurityConfigurationResponse,
AdminSystemWriteGovernanceResponse,
)
from admin_app.core import AdminSecurityService, AuthenticatedStaffPrincipal
from admin_app.core.settings import AdminSettings
from admin_app.services.system_service import SystemService
from shared.contracts import AdminPermission
# governança e configuração do sistema.
router = APIRouter(tags=["system"])
def _build_service(
settings: AdminSettings,
security_service: AdminSecurityService,
) -> SystemService:
return SystemService(settings=settings, security_service=security_service)
@router.get("/", response_model=None)
def root(
request: Request,
settings: AdminSettings = Depends(get_settings),
) -> Response | dict:
if "text/html" in request.headers.get("accept", ""):
return RedirectResponse(
url=_build_prefixed_path(settings.admin_api_prefix, "/login"),
status_code=302,
)
return SystemService(settings=settings).build_root_payload()
@router.get("/health", response_model=AdminHealthResponse)
def health_check(settings: AdminSettings = Depends(get_settings)):
return SystemService(settings=settings).build_health_payload()
@router.get(
"/system/info",
response_model=AdminSystemInfoResponse,
)
def system_info(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.VIEW_SYSTEM)
),
):
return _build_service(settings, security_service).build_system_info_payload()
@router.get(
"/system/access",
response_model=AdminCurrentAccessResponse,
)
def current_access(
current_staff: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.VIEW_SYSTEM)
),
permissions: tuple[str, ...] = Depends(get_current_staff_permissions),
):
return AdminCurrentAccessResponse(
service="orquestrador-admin",
staff_account={
"id": current_staff.id,
"email": current_staff.email,
"display_name": current_staff.display_name,
"role": current_staff.role,
"is_active": current_staff.is_active,
},
permissions=list(permissions),
)
@router.get(
"/system/admin-capabilities",
response_model=AdminCapabilityResponse,
)
def admin_capabilities(
current_staff: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
return AdminCapabilityResponse(
service="orquestrador-admin",
action="manage_settings",
allowed=True,
role=current_staff.role,
)
@router.get(
"/system/configuration",
response_model=AdminSystemConfigurationResponse,
)
def system_configuration(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
service = _build_service(settings, security_service)
runtime_payload = _build_runtime_configuration_payload(service, settings)
return AdminSystemConfigurationResponse(
service="orquestrador-admin",
runtime=runtime_payload,
security=service.build_security_configuration_payload(),
model_runtimes=service.build_model_runtime_separation_payload(),
write_governance=service.build_write_governance_payload(),
sources=service.build_configuration_sources_payload(),
)
@router.get(
"/system/configuration/runtime",
response_model=AdminSystemRuntimeConfigurationResponse,
)
def system_runtime_configuration(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
service = _build_service(settings, security_service)
return AdminSystemRuntimeConfigurationResponse(
service="orquestrador-admin",
runtime=_build_runtime_configuration_payload(service, settings),
)
@router.get(
"/system/configuration/security",
response_model=AdminSystemSecurityConfigurationResponse,
)
def system_security_configuration(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
service = _build_service(settings, security_service)
return AdminSystemSecurityConfigurationResponse(
service="orquestrador-admin",
security=service.build_security_configuration_payload(),
)
@router.get(
"/system/configuration/model-runtimes",
response_model=AdminSystemModelRuntimeSeparationResponse,
)
def system_model_runtime_separation(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
service = _build_service(settings, security_service)
return AdminSystemModelRuntimeSeparationResponse(
service="orquestrador-admin",
model_runtimes=service.build_model_runtime_separation_payload(),
)
@router.get(
"/system/configuration/write-governance",
response_model=AdminSystemWriteGovernanceResponse,
)
def system_write_governance_configuration(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.MANAGE_SETTINGS)
),
):
service = _build_service(settings, security_service)
return AdminSystemWriteGovernanceResponse(
service="orquestrador-admin",
write_governance=service.build_write_governance_payload(),
)
@router.get(
"/system/configuration/functional",
response_model=AdminSystemFunctionalConfigurationCatalogResponse,
)
def system_functional_configuration_catalog(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.VIEW_SYSTEM)
),
):
service = _build_service(settings, security_service)
payload = service.build_functional_configuration_catalog_payload()
return AdminSystemFunctionalConfigurationCatalogResponse(
service="orquestrador-admin",
mode=payload["mode"],
configurations=payload["configurations"],
bot_governed_parent_config_keys=payload["bot_governed_parent_config_keys"],
next_steps=payload["next_steps"],
)
@router.get(
"/system/configuration/functional/bot-governance",
response_model=AdminSystemBotGovernedConfigurationResponse,
)
def system_bot_governed_configuration(
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.VIEW_SYSTEM)
),
):
service = _build_service(settings, security_service)
payload = service.build_bot_governed_configuration_payload()
return AdminSystemBotGovernedConfigurationResponse(
service="orquestrador-admin",
parent_config_keys=payload["parent_config_keys"],
settings=payload["settings"],
)
@router.get(
"/system/configuration/functional/{config_key}",
response_model=AdminSystemFunctionalConfigurationDetailResponse,
)
def system_functional_configuration_detail(
config_key: str,
settings: AdminSettings = Depends(get_settings),
security_service: AdminSecurityService = Depends(get_security_service),
_: AuthenticatedStaffPrincipal = Depends(
require_admin_permission(AdminPermission.VIEW_SYSTEM)
),
):
service = _build_service(settings, security_service)
payload = service.get_functional_configuration_payload(config_key)
if payload is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Configuracao funcional do sistema nao encontrada.",
)
return AdminSystemFunctionalConfigurationDetailResponse(
service="orquestrador-admin",
configuration=payload["configuration"],
linked_bot_settings=payload["linked_bot_settings"],
related_runtime_profile=payload["related_runtime_profile"],
managed_by_bot_governance=payload["managed_by_bot_governance"],
)
def _build_runtime_configuration_payload(
service: SystemService,
settings: AdminSettings,
) -> dict:
runtime_payload = service.build_runtime_configuration_payload()
runtime_payload["panel_session"] = {
"access_cookie_name": PANEL_ACCESS_COOKIE_NAME,
"refresh_cookie_name": PANEL_REFRESH_COOKIE_NAME,
"cookie_path": build_panel_cookie_path(settings),
"same_site": PANEL_COOKIE_SAMESITE,
"secure_cookies": should_use_secure_cookies(settings),
}
return runtime_payload
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}"