feat: tela Minha conta para trocar a propria senha

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Gustavo
2026-08-13 20:44:15 -03:00
co-authored by Claude Sonnet 5
parent c4079b3e47
commit 4a5c70861d
3 changed files with 248 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
"""
Tela "Minha conta" — qualquer usuário logado (admin ou padrão) troca a
própria senha aqui, sem precisar de um admin. Pede a senha atual antes de
trocar, mesmo já estando logado (proteção extra contra sessão esquecida
aberta em máquina compartilhada).
A conta de bootstrap (ADMIN_USER/ADMIN_PASSWORD do .env) não tem linha em
FUNCIONARIO_PAINEL — não há senha para trocar pelo painel; a tela avisa
que a troca é editando o .env do servidor.
"""
from fastapi import APIRouter, Depends, Form, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from ..auth import UsuarioLogado, exigir_login
from ..csrf import exigir_csrf, token_do_contexto
from ..db import funcionarios as db_funcionarios
from ..db import log as db_log
from ..senha import verificar_senha
router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
@router.get("/minha-conta", response_class=HTMLResponse)
def form_minha_conta(request: Request, usuario: UsuarioLogado = Depends(exigir_login)):
funcionario = db_funcionarios.obter_por_login(usuario.login)
return templates.TemplateResponse(
request,
"minha_conta.html",
{
"usuario_atual": usuario, "eh_conta_env": funcionario is None,
"csrf_token": token_do_contexto(request),
},
)
@router.post("/minha-conta/senha", dependencies=[Depends(exigir_csrf)])
def trocar_senha(
request: Request,
senha_atual: str = Form(...),
nova_senha: str = Form(...),
confirmar_nova_senha: str = Form(...),
usuario: UsuarioLogado = Depends(exigir_login),
):
funcionario = db_funcionarios.obter_por_login(usuario.login)
erro = None
if funcionario is None:
erro = "Esta conta é configurada por variável de ambiente (.env) — troque a senha lá, não por aqui."
elif not verificar_senha(senha_atual, funcionario["SENHA_HASH"]):
erro = "A senha atual digitada não confere."
elif not nova_senha or nova_senha != confirmar_nova_senha:
erro = "A nova senha e a confirmação não coincidem."
if erro:
return templates.TemplateResponse(
request,
"minha_conta.html",
{
"usuario_atual": usuario, "eh_conta_env": funcionario is None, "erro": erro,
"csrf_token": token_do_contexto(request),
},
)
db_funcionarios.redefinir_senha(funcionario["ID"], nova_senha)
db_log.registrar(str(usuario), "trocar_senha", "funcionario", str(funcionario["ID"]), True)
return templates.TemplateResponse(
request,
"minha_conta.html",
{
"usuario_atual": usuario, "eh_conta_env": False, "mensagem": "Senha alterada com sucesso.",
"csrf_token": token_do_contexto(request),
},
)