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.
641 lines
27 KiB
Python
641 lines
27 KiB
Python
from fastapi import APIRouter, Depends, Request
|
|
from fastapi.responses import HTMLResponse, RedirectResponse, Response
|
|
|
|
from admin_app.api.dependencies import get_optional_panel_staff_context
|
|
from admin_app.core import AdminSettings, AuthenticatedStaffContext, get_admin_settings
|
|
from admin_app.services import ToolManagementService
|
|
from admin_app.view.assets import PANEL_STATIC_MOUNT_NAME
|
|
from admin_app.view.rendering import (
|
|
render_collaborator_management_page,
|
|
render_login_page,
|
|
render_panel_home,
|
|
render_tool_intake_page,
|
|
render_tool_review_page,
|
|
)
|
|
from admin_app.view.view_models import (
|
|
AdminCollaboratorManagementPageView,
|
|
AdminLoginPageView,
|
|
AdminPanelHomeView,
|
|
AdminPanelMetric,
|
|
AdminPanelModuleCard,
|
|
AdminPanelNavigationItem,
|
|
AdminPanelQuickAction,
|
|
AdminPanelRoadmapItem,
|
|
AdminPanelSurfaceLink,
|
|
AdminToolIntakeDomainOption,
|
|
AdminToolIntakePageView,
|
|
AdminToolIntakeParameterTypeOption,
|
|
AdminToolReviewPageView,
|
|
AdminToolReviewWorkflowStep,
|
|
)
|
|
from shared.contracts import AdminPermission, StaffRole, role_has_permission
|
|
|
|
panel_router = APIRouter(tags=["panel"])
|
|
|
|
|
|
@panel_router.get("/panel", name="panel_entry")
|
|
def panel_entry(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> RedirectResponse:
|
|
target_route_name = "panel_home" if current_context is not None else "admin_login_view"
|
|
return _redirect_to_route(request, target_route_name)
|
|
|
|
|
|
@panel_router.get("/panel/admin", response_class=HTMLResponse, name="panel_home")
|
|
def panel_home(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> Response:
|
|
if current_context is None:
|
|
return _redirect_to_route(request, "admin_login_view")
|
|
|
|
settings = _resolve_settings(request)
|
|
view = _build_home_view(request, settings, current_context)
|
|
css_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="styles/panel.css"))
|
|
js_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="scripts/panel.js"))
|
|
return HTMLResponse(render_panel_home(view, css_href=css_href, js_href=js_href))
|
|
|
|
|
|
@panel_router.get("/login", response_class=HTMLResponse, name="admin_login_view")
|
|
def login_page(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> Response:
|
|
if current_context is not None:
|
|
return _redirect_to_route(request, "panel_home")
|
|
|
|
settings = _resolve_settings(request)
|
|
view = _build_login_view(request, settings)
|
|
css_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="styles/panel.css"))
|
|
js_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="scripts/panel.js"))
|
|
return HTMLResponse(render_login_page(view, css_href=css_href, js_href=js_href))
|
|
|
|
|
|
@panel_router.get("/panel/tools/new", response_class=HTMLResponse, name="admin_tool_intake_view")
|
|
def tool_intake_page(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> Response:
|
|
if current_context is None:
|
|
return _redirect_to_route(request, "admin_login_view")
|
|
|
|
settings = _resolve_settings(request)
|
|
view = _build_tool_intake_view(request, settings)
|
|
css_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="styles/panel.css"))
|
|
js_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="scripts/panel.js"))
|
|
return HTMLResponse(render_tool_intake_page(view, css_href=css_href, js_href=js_href))
|
|
|
|
|
|
@panel_router.get("/panel/tools/review", response_class=HTMLResponse, name="admin_tool_review_view")
|
|
def tool_review_page(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> Response:
|
|
if current_context is None:
|
|
return _redirect_to_route(request, "admin_login_view")
|
|
|
|
settings = _resolve_settings(request)
|
|
view = _build_tool_review_view(request, settings)
|
|
css_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="styles/panel.css"))
|
|
js_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="scripts/panel.js"))
|
|
return HTMLResponse(render_tool_review_page(view, css_href=css_href, js_href=js_href))
|
|
|
|
|
|
@panel_router.get("/panel/colaboradores/gestao", response_class=HTMLResponse, name="admin_collaborator_management_view")
|
|
def collaborator_management_page(
|
|
request: Request,
|
|
current_context: AuthenticatedStaffContext | None = Depends(get_optional_panel_staff_context),
|
|
) -> Response:
|
|
if current_context is None:
|
|
return _redirect_to_route(request, "admin_login_view")
|
|
if not role_has_permission(current_context.principal.role, AdminPermission.MANAGE_STAFF_ACCOUNTS):
|
|
return _redirect_to_route(request, "panel_home")
|
|
|
|
settings = _resolve_settings(request)
|
|
view = _build_collaborator_management_view(request, settings)
|
|
css_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="styles/panel.css"))
|
|
js_href = str(request.url_for(PANEL_STATIC_MOUNT_NAME, path="scripts/panel.js"))
|
|
return HTMLResponse(render_collaborator_management_page(view, css_href=css_href, js_href=js_href))
|
|
|
|
|
|
def _build_home_view(
|
|
request: Request,
|
|
settings: AdminSettings,
|
|
current_context: AuthenticatedStaffContext,
|
|
) -> AdminPanelHomeView:
|
|
panel_href = str(request.url_for("panel_home"))
|
|
tool_intake_view_href = str(request.url_for("admin_tool_intake_view"))
|
|
tool_review_view_href = str(request.url_for("admin_tool_review_view"))
|
|
collaborator_management_view_href = str(request.url_for("admin_collaborator_management_view"))
|
|
system_configuration_href = _build_prefixed_path(settings.admin_api_prefix, "/system/configuration")
|
|
audit_href = _build_prefixed_path(settings.admin_api_prefix, "/audit/events")
|
|
can_manage_collaborators = role_has_permission(
|
|
current_context.principal.role,
|
|
AdminPermission.MANAGE_STAFF_ACCOUNTS,
|
|
)
|
|
|
|
navigation = [
|
|
AdminPanelNavigationItem(
|
|
label="Dashboard",
|
|
href=panel_href,
|
|
description="Entrada principal do ambiente interno.",
|
|
badge="Ativo",
|
|
is_active=True,
|
|
),
|
|
AdminPanelNavigationItem(
|
|
label="Cadastro de tools",
|
|
href=tool_intake_view_href,
|
|
description="Pre-cadastro validado para novas tools antes da revisao.",
|
|
badge="Novo",
|
|
),
|
|
AdminPanelNavigationItem(
|
|
label="Revisao de tools",
|
|
href=tool_review_view_href,
|
|
description="Fluxo humano de revisao, aprovacao e ativacao.",
|
|
badge="Operacao",
|
|
),
|
|
AdminPanelNavigationItem(
|
|
label="Areas do sistema",
|
|
href="#modules",
|
|
description="Mapa claro dos modulos internos disponiveis.",
|
|
badge="Painel",
|
|
),
|
|
AdminPanelNavigationItem(
|
|
label="Fluxo recomendado",
|
|
href="#workflow",
|
|
description="Sequencia sugerida para operar o admin.",
|
|
badge="Guia",
|
|
),
|
|
]
|
|
quick_actions = [
|
|
AdminPanelQuickAction(
|
|
label="Cadastrar tool",
|
|
href=tool_intake_view_href,
|
|
button_class="btn-dark",
|
|
),
|
|
AdminPanelQuickAction(
|
|
label="Revisar tools",
|
|
href=tool_review_view_href,
|
|
button_class="btn-outline-dark",
|
|
),
|
|
AdminPanelQuickAction(
|
|
label="Ver areas",
|
|
href="#modules",
|
|
button_class="btn-outline-secondary",
|
|
),
|
|
]
|
|
modules = [
|
|
AdminPanelModuleCard(
|
|
eyebrow="Fluxo de entrada",
|
|
title="Cadastro de tools",
|
|
description="Tela real para o colaborador preencher metadados, definir parametros e validar o pre-cadastro antes da revisao humana.",
|
|
status_label="Tela ativa",
|
|
status_variant="success",
|
|
highlights=(
|
|
"Formulario protegido por sessao web",
|
|
"Preview validado antes da persistencia",
|
|
"Direcao clara para revisao de diretor",
|
|
),
|
|
cta_label="Abrir cadastro",
|
|
href=tool_intake_view_href,
|
|
is_available=True,
|
|
),
|
|
AdminPanelModuleCard(
|
|
eyebrow="Fluxo principal",
|
|
title="Revisao de tools",
|
|
description="Area operacional do painel para leitura da fila, aprovacao humana e ativacao controlada.",
|
|
status_label="Tela ativa",
|
|
status_variant="success",
|
|
highlights=(
|
|
"Fila protegida por sessao web",
|
|
"Catalogo ativo para comparacao",
|
|
"Leitura clara do workflow de aprovacao",
|
|
),
|
|
cta_label="Abrir revisao",
|
|
href=tool_review_view_href,
|
|
is_available=True,
|
|
),
|
|
AdminPanelModuleCard(
|
|
eyebrow="Acompanhamento",
|
|
title="Configuracao do sistema",
|
|
description="Snapshot do runtime administrativo, politicas de seguranca e dados de sessao do painel.",
|
|
status_label="API pronta",
|
|
status_variant="secondary",
|
|
highlights=(
|
|
"Runtime e banco monitorados",
|
|
"Politicas de credencial centralizadas",
|
|
"Base pronta para futura tela dedicada",
|
|
),
|
|
),
|
|
AdminPanelModuleCard(
|
|
eyebrow="Governanca",
|
|
title="Auditoria operacional",
|
|
description="Eventos de login, logout, aprovacao e publicacao continuam registrados para rastreabilidade.",
|
|
status_label="Auditavel",
|
|
status_variant="secondary",
|
|
highlights=(
|
|
"Historico de operacao interna",
|
|
"Base para filtros e timeline",
|
|
"Suporte a conformidade do fluxo administrativo",
|
|
),
|
|
),
|
|
]
|
|
surface_links = [
|
|
AdminPanelSurfaceLink(
|
|
method="Acesso",
|
|
label="Dashboard administrativa",
|
|
href=panel_href,
|
|
description="Entrada principal do time interno depois do login.",
|
|
),
|
|
AdminPanelSurfaceLink(
|
|
method="Cadastro",
|
|
label="Nova tool",
|
|
href=tool_intake_view_href,
|
|
description="Formulario real para validar o pre-cadastro de uma nova tool.",
|
|
),
|
|
AdminPanelSurfaceLink(
|
|
method="Operacao",
|
|
label="Revisao de tools",
|
|
href=tool_review_view_href,
|
|
description="Area com fila, contrato e catalogo ativo para tomada de decisao.",
|
|
),
|
|
AdminPanelSurfaceLink(
|
|
method="Runtime",
|
|
label="Configuracao do sistema",
|
|
href=system_configuration_href,
|
|
description="Snapshot tecnico do ambiente, mantido como superficie protegida enquanto a tela visual nao chega.",
|
|
),
|
|
AdminPanelSurfaceLink(
|
|
method="Auditoria",
|
|
label="Eventos administrativos",
|
|
href=audit_href,
|
|
description="Consulta de eventos internos para rastrear operacoes sensiveis.",
|
|
),
|
|
]
|
|
roadmap = [
|
|
AdminPanelRoadmapItem(
|
|
step="01",
|
|
title="Entrar pelo login administrativo",
|
|
description="A sessao web libera o ambiente interno e evita navegacao confusa antes da autenticacao.",
|
|
status_label="Obrigatorio",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="02",
|
|
title="Passar pela dashboard",
|
|
description="A home protegida organiza os modulos e mostra por onde comecar a operacao.",
|
|
status_label="Entrada",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="03",
|
|
title="Cadastrar ou validar o pre-draft",
|
|
description="Use a nova tela para descrever a tool, seus parametros e o objetivo operacional antes da revisao.",
|
|
status_label="Cadastro",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="04",
|
|
title="Abrir revisao de tools",
|
|
description="Encaminhe a ferramenta para analise humana, aprovacao e ativacao controlada.",
|
|
status_label="Principal",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="05",
|
|
title="Consultar runtime e auditoria",
|
|
description="Quando necessario, acompanhe configuracao e eventos do admin para suportar a decisao operacional.",
|
|
status_label="Suporte",
|
|
),
|
|
]
|
|
|
|
if can_manage_collaborators:
|
|
navigation.insert(
|
|
3,
|
|
AdminPanelNavigationItem(
|
|
label="Colaboradores",
|
|
href=collaborator_management_view_href,
|
|
description="Cadastro e governanca de acessos internos, exclusivo para diretor.",
|
|
badge="Diretor",
|
|
),
|
|
)
|
|
quick_actions.insert(
|
|
2,
|
|
AdminPanelQuickAction(
|
|
label="Gerir equipe",
|
|
href=collaborator_management_view_href,
|
|
button_class="btn-outline-dark",
|
|
),
|
|
)
|
|
modules.insert(
|
|
2,
|
|
AdminPanelModuleCard(
|
|
eyebrow="Governanca de acesso",
|
|
title="Gestao de colaboradores",
|
|
description="Tela dedicada para o diretor criar contas internas, acompanhar o status da equipe e manter a entrada administrativa sob controle.",
|
|
status_label="Tela ativa",
|
|
status_variant="dark",
|
|
highlights=(
|
|
"Criacao de colaborador com senha inicial",
|
|
"Ativacao e desativacao sem tocar no banco manualmente",
|
|
"Fluxo exclusivo para diretor",
|
|
),
|
|
cta_label="Abrir equipe",
|
|
href=collaborator_management_view_href,
|
|
is_available=True,
|
|
),
|
|
)
|
|
surface_links.insert(
|
|
3,
|
|
AdminPanelSurfaceLink(
|
|
method="Equipe",
|
|
label="Gestao de colaboradores",
|
|
href=collaborator_management_view_href,
|
|
description="Controle de acesso interno para cadastrar e administrar a equipe administrativa.",
|
|
),
|
|
)
|
|
roadmap = [
|
|
AdminPanelRoadmapItem(
|
|
step="01",
|
|
title="Entrar pelo login administrativo",
|
|
description="A sessao web libera o ambiente interno e evita navegacao confusa antes da autenticacao.",
|
|
status_label="Obrigatorio",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="02",
|
|
title="Passar pela dashboard",
|
|
description="A home protegida organiza os modulos e mostra por onde comecar a operacao.",
|
|
status_label="Entrada",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="03",
|
|
title="Cadastrar ou validar o pre-draft",
|
|
description="Use a nova tela para descrever a tool, seus parametros e o objetivo operacional antes da revisao.",
|
|
status_label="Cadastro",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="04",
|
|
title="Organizar a equipe interna",
|
|
description="Diretores podem cadastrar novos colaboradores e controlar rapidamente o status de acesso administrativo.",
|
|
status_label="Diretor",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="05",
|
|
title="Abrir revisao de tools",
|
|
description="Encaminhe a ferramenta para analise humana, aprovacao e ativacao controlada.",
|
|
status_label="Principal",
|
|
),
|
|
AdminPanelRoadmapItem(
|
|
step="06",
|
|
title="Consultar runtime e auditoria",
|
|
description="Quando necessario, acompanhe configuracao e eventos do admin para suportar a decisao operacional.",
|
|
status_label="Suporte",
|
|
),
|
|
]
|
|
|
|
return AdminPanelHomeView(
|
|
service="orquestrador-admin",
|
|
app_name=settings.admin_app_name,
|
|
panel_title="Painel Administrativo",
|
|
panel_subtitle=(
|
|
"Area interna protegida para operar o admin com mais clareza, foco e navegacao orientada por fluxo."
|
|
),
|
|
environment=settings.admin_environment,
|
|
version=settings.admin_version,
|
|
api_prefix=settings.admin_api_prefix or "/",
|
|
release_label="Bootstrap UI v1",
|
|
navigation=tuple(navigation),
|
|
quick_actions=tuple(quick_actions),
|
|
metrics=(
|
|
AdminPanelMetric(
|
|
label="Runtimes independentes",
|
|
value="2",
|
|
description="Produto e admin seguem isolados para deploy e operacao.",
|
|
),
|
|
AdminPanelMetric(
|
|
label="Perfis internos",
|
|
value=str(len(StaffRole)),
|
|
description="Hierarquia base com colaborador e diretor.",
|
|
),
|
|
AdminPanelMetric(
|
|
label="Permissoes administrativas",
|
|
value=str(len(AdminPermission)),
|
|
description="Camada pronta para crescer por modulo sem misturar contexto.",
|
|
),
|
|
AdminPanelMetric(
|
|
label="Refresh token",
|
|
value=f"{settings.admin_auth_refresh_token_ttl_days} dias",
|
|
description="Sessao web persistida com renovacao controlada.",
|
|
),
|
|
),
|
|
modules=tuple(modules),
|
|
surface_links=tuple(surface_links),
|
|
roadmap=tuple(roadmap),
|
|
)
|
|
|
|
|
|
def _build_login_view(request: Request, settings: AdminSettings) -> AdminLoginPageView:
|
|
dashboard_href = str(request.url_for("panel_home"))
|
|
auth_endpoint = _build_prefixed_path(settings.admin_api_prefix, "/panel/auth/login")
|
|
password_requirements = []
|
|
if settings.admin_auth_password_require_uppercase:
|
|
password_requirements.append("maiuscula")
|
|
if settings.admin_auth_password_require_lowercase:
|
|
password_requirements.append("minuscula")
|
|
if settings.admin_auth_password_require_digit:
|
|
password_requirements.append("digito")
|
|
if settings.admin_auth_password_require_symbol:
|
|
password_requirements.append("simbolo")
|
|
|
|
password_policy_label = (
|
|
f"Minimo de {settings.admin_auth_password_min_length} caracteres"
|
|
+ (f" com {', '.join(password_requirements)}." if password_requirements else ".")
|
|
)
|
|
|
|
return AdminLoginPageView(
|
|
app_name=settings.admin_app_name,
|
|
title="Login administrativo",
|
|
subtitle=(
|
|
"Entre primeiro com sua conta interna. A dashboard e os modulos do sistema so aparecem depois da autenticacao."
|
|
),
|
|
environment=settings.admin_environment,
|
|
version=settings.admin_version,
|
|
dashboard_href=dashboard_href,
|
|
auth_endpoint=auth_endpoint,
|
|
email_placeholder="voce@empresa.com",
|
|
password_placeholder="Sua senha administrativa",
|
|
access_token_ttl_label=f"{settings.admin_auth_access_token_ttl_minutes} minutos",
|
|
refresh_token_ttl_label=f"{settings.admin_auth_refresh_token_ttl_days} dias",
|
|
password_policy_label=password_policy_label,
|
|
security_highlights=(
|
|
"Identidade separada do usuario de atendimento",
|
|
"Rotacao de refresh token ja implementada",
|
|
"Trilha de auditoria para login e logout",
|
|
),
|
|
integration_notes=(
|
|
"A dashboard administrativa so aparece depois da autenticacao do StaffAccount.",
|
|
"Revisao, configuracao e operacao interna ficam atras da sessao web do painel.",
|
|
"Cookies httpOnly e refresh token rotacionado mantem a sessao do navegador protegida.",
|
|
),
|
|
)
|
|
|
|
|
|
def _build_tool_intake_view(request: Request, settings: AdminSettings) -> AdminToolIntakePageView:
|
|
service = ToolManagementService(settings)
|
|
form_payload = service.build_draft_form_payload()
|
|
|
|
return AdminToolIntakePageView(
|
|
app_name=settings.admin_app_name,
|
|
title="Cadastro de nova tool",
|
|
subtitle=(
|
|
"Formulario guiado para o colaborador estruturar uma nova tool, validar o pre-draft e encaminhar a proposta para revisao de diretor."
|
|
),
|
|
environment=settings.admin_environment,
|
|
version=settings.admin_version,
|
|
dashboard_href=str(request.url_for("panel_home")),
|
|
review_href=str(request.url_for("admin_tool_review_view")),
|
|
intake_endpoint=_build_prefixed_path(settings.admin_api_prefix, "/panel/tools/drafts/intake"),
|
|
domain_options=tuple(
|
|
AdminToolIntakeDomainOption(
|
|
value=item["value"],
|
|
label=item["label"],
|
|
description=item["description"],
|
|
)
|
|
for item in form_payload["domain_options"]
|
|
),
|
|
parameter_type_options=tuple(
|
|
AdminToolIntakeParameterTypeOption(
|
|
value=item["code"].value,
|
|
label=item["label"],
|
|
description=item["description"],
|
|
)
|
|
for item in form_payload["parameter_types"]
|
|
),
|
|
naming_rules=tuple(form_payload["naming_rules"]),
|
|
submission_notes=tuple(form_payload["submission_notes"]),
|
|
approval_notes=tuple(form_payload["approval_notes"]),
|
|
)
|
|
|
|
|
|
def _build_tool_review_view(request: Request, settings: AdminSettings) -> AdminToolReviewPageView:
|
|
dashboard_href = str(request.url_for("panel_home"))
|
|
overview_endpoint = _build_prefixed_path(settings.admin_api_prefix, "/panel/tools/overview")
|
|
contracts_endpoint = _build_prefixed_path(settings.admin_api_prefix, "/panel/tools/contracts")
|
|
review_queue_endpoint = _build_prefixed_path(settings.admin_api_prefix, "/panel/tools/review-queue")
|
|
publications_endpoint = _build_prefixed_path(settings.admin_api_prefix, "/panel/tools/publications")
|
|
|
|
return AdminToolReviewPageView(
|
|
app_name=settings.admin_app_name,
|
|
title="Revisao, aprovacao e ativacao",
|
|
subtitle=(
|
|
"Hub visual para o time interno acompanhar a fila de revisao, validar o contrato compartilhado e inspecionar o catalogo de tools ativas antes da ativacao."
|
|
),
|
|
environment=settings.admin_environment,
|
|
version=settings.admin_version,
|
|
dashboard_href=dashboard_href,
|
|
overview_endpoint=overview_endpoint,
|
|
contracts_endpoint=contracts_endpoint,
|
|
review_queue_endpoint=review_queue_endpoint,
|
|
publications_endpoint=publications_endpoint,
|
|
workflow=(
|
|
AdminToolReviewWorkflowStep(
|
|
eyebrow="Leitura inicial",
|
|
title="Revisar fila",
|
|
description="Carregar a fila de geracao e entender em que gate cada item se encontra.",
|
|
status_label="Revisao",
|
|
status_variant="info",
|
|
),
|
|
AdminToolReviewWorkflowStep(
|
|
eyebrow="Decisao humana",
|
|
title="Aprovar com criterio",
|
|
description="Conferir contrato, parametros e prontidao tecnica antes de liberar a proxima etapa.",
|
|
status_label="Aprovacao",
|
|
status_variant="warning",
|
|
),
|
|
AdminToolReviewWorkflowStep(
|
|
eyebrow="Publicacao",
|
|
title="Ativar no catalogo",
|
|
description="Usar o catalogo publicado como referencia para a versao que chega ao runtime de produto.",
|
|
status_label="Ativacao",
|
|
status_variant="success",
|
|
),
|
|
),
|
|
review_notes=(
|
|
"Conferir se o gate do item combina com o estado esperado do lifecycle.",
|
|
"Observar se a descricao e o objetivo operacional da tool estao claros para o time.",
|
|
"Usar o catalogo ativo como comparativo antes de promover uma nova versao.",
|
|
),
|
|
approval_notes=(
|
|
"Verificar nome, descricao e semantica dos parametros antes da aprovacao.",
|
|
"Confirmar se a tool respeita a separacao entre admin e product definida nas ADRs.",
|
|
"Checar se a publicacao planejada e auditavel e segura para o runtime de produto.",
|
|
),
|
|
activation_notes=(
|
|
"Publicacoes ativas exigem papel com permissao publish_tools.",
|
|
"A leitura do catalogo e feita via sessao web do painel para facilitar a operacao do navegador.",
|
|
"Sem permissao de publicacao, a tela continua util para revisao, mas bloqueia o catalogo ativo.",
|
|
),
|
|
)
|
|
|
|
|
|
def _build_collaborator_management_view(
|
|
request: Request,
|
|
settings: AdminSettings,
|
|
) -> AdminCollaboratorManagementPageView:
|
|
password_requirements = []
|
|
if settings.admin_auth_password_require_uppercase:
|
|
password_requirements.append("maiuscula")
|
|
if settings.admin_auth_password_require_lowercase:
|
|
password_requirements.append("minuscula")
|
|
if settings.admin_auth_password_require_digit:
|
|
password_requirements.append("digito")
|
|
if settings.admin_auth_password_require_symbol:
|
|
password_requirements.append("simbolo")
|
|
|
|
password_policy_label = (
|
|
f"Minimo de {settings.admin_auth_password_min_length} caracteres"
|
|
+ (f" com {', '.join(password_requirements)}." if password_requirements else ".")
|
|
)
|
|
|
|
return AdminCollaboratorManagementPageView(
|
|
app_name=settings.admin_app_name,
|
|
title="Gestao de colaboradores",
|
|
subtitle=(
|
|
"Tela exclusiva de diretor para organizar a equipe interna, criar novos acessos administrativos e controlar rapidamente quem segue ativo no painel."
|
|
),
|
|
environment=settings.admin_environment,
|
|
version=settings.admin_version,
|
|
dashboard_href=str(request.url_for("panel_home")),
|
|
collection_endpoint=_build_prefixed_path(settings.admin_api_prefix, "/panel/colaboradores"),
|
|
password_policy_label=password_policy_label,
|
|
onboarding_notes=(
|
|
"Novos acessos nascem sempre com papel de colaborador.",
|
|
"A senha inicial ja respeita a mesma politica do login administrativo.",
|
|
"Ativar ou desativar colaborador nao exige acesso direto ao banco.",
|
|
),
|
|
governance_notes=(
|
|
"Somente diretor acessa esta tela e as rotas de gestao de colaboradores.",
|
|
"Cada criacao e alteracao de status gera trilha de auditoria administrativa.",
|
|
"A conta de diretor continua fora deste fluxo para evitar mudancas acidentais na governanca principal.",
|
|
),
|
|
)
|
|
|
|
|
|
def _redirect_to_route(request: Request, route_name: str) -> RedirectResponse:
|
|
return RedirectResponse(url=str(request.url_for(route_name)), status_code=302)
|
|
|
|
|
|
def _resolve_settings(request: Request) -> AdminSettings:
|
|
app_settings = getattr(request.app.state, "admin_settings", None)
|
|
if isinstance(app_settings, AdminSettings):
|
|
return app_settings
|
|
return get_admin_settings()
|
|
|
|
|
|
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}"
|
|
|