base.html usava {{ csrf_token }}, variavel que so algumas rotas passam
explicitamente no contexto do template. Em /clientes (GET), /log e
/gerador-chave a variavel nunca era passada, entao o campo oculto do
formulario de logout renderizava com value="" e exigir_csrf (app/csrf.py)
rejeitava o POST /logout com 403 - o usuario nao conseguia clicar em
'Sair' logo apos logar, ja que /clientes e para onde todo login cai.
Corrige na raiz: usa {{ csrf_token or request.state.csrf_token }}, caindo
para o valor que csrf_cookie_middleware (app/main.py) ja popula em toda
requisicao quando a rota nao passar csrf_token explicitamente. Protege
tambem qualquer rota futura que esqueca de passar a variavel.
Testes de regressao em tests/test_main.py: confirma que GET /clientes
renderiza um csrf_token nao vazio no formulario de logout, e que
POST /logout funciona (303) apos visitar /clientes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
2.4 KiB
HTML
49 lines
2.4 KiB
HTML
<!-- app/templates/base.html -->
|
|
<!DOCTYPE html>
|
|
<html lang="pt-BR">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>{% block titulo %}Painel de Clientes{% endblock %}</title>
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; margin: 0; background: #17171a; color: #f4f4f5; }
|
|
nav { background: #232326; padding: 12px 20px; display: flex; gap: 16px; }
|
|
nav a { color: #f4f4f5; text-decoration: none; }
|
|
nav a:hover { color: #F5821F; }
|
|
main { padding: 20px; max-width: 960px; margin: 0 auto; }
|
|
table { width: 100%; border-collapse: collapse; margin-top: 12px; }
|
|
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #3a3a3e; }
|
|
th a { color: inherit; text-decoration: none; white-space: nowrap; }
|
|
th a:hover { color: #F5821F; }
|
|
input, select { padding: 8px; border-radius: 6px; border: 1px solid #3a3a3e; background: #17171a; color: #f4f4f5; width: 100%; box-sizing: border-box; }
|
|
label { display: block; margin-top: 10px; font-size: 0.85rem; color: #a1a1aa; }
|
|
button { margin-top: 14px; padding: 10px 16px; border: none; border-radius: 6px; background: #F5821F; color: #17171a; font-weight: 700; cursor: pointer; }
|
|
.mensagem { padding: 10px; border-radius: 6px; margin-bottom: 12px; }
|
|
.mensagem.success { background: #14532d; }
|
|
.mensagem.danger { background: #7f1d1d; }
|
|
.mensagem.warning { background: #78350f; }
|
|
a.botao { display: inline-block; padding: 6px 10px; border: 1px solid #3a3a3e; border-radius: 6px; color: #f4f4f5; text-decoration: none; margin-right: 6px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<nav>
|
|
<a href="/clientes">Clientes</a>
|
|
<a href="/gerador-chave">Gerador de chave</a>
|
|
{% if request.state.usuario and request.state.usuario.eh_admin %}
|
|
<a href="/funcionarios">Funcionários</a>
|
|
{% endif %}
|
|
<a href="/log">Log</a>
|
|
{% if request.state.usuario %}
|
|
<a href="/minha-conta">Minha conta</a>
|
|
<form method="post" action="/logout" style="display:inline;margin:0">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token or request.state.csrf_token }}">
|
|
<button type="submit" style="margin:0;padding:4px 10px;background:transparent;border:1px solid #3a3a3e;color:#f4f4f5;font-weight:400">Sair</button>
|
|
</form>
|
|
{% endif %}
|
|
</nav>
|
|
<main>
|
|
{% if mensagem %}<div class="mensagem {{ mensagem_tipo or 'success' }}">{{ mensagem }}</div>{% endif %}
|
|
{% block conteudo %}{% endblock %}
|
|
</main>
|
|
</body>
|
|
</html>
|