| | |
| | import os |
| | import streamlit as st |
| |
|
| | from banco import SessionLocal |
| | from models import Usuario |
| | from utils_seguranca import verificar_senha |
| | from utils_auditoria import registrar_log |
| |
|
| | |
| | |
| | try: |
| | from db_router import ( |
| | set_db_choice, |
| | current_db_choice, |
| | list_banks, |
| | bank_label, |
| | get_session_for_current_db, |
| | ) |
| | _HAS_ROUTER = True |
| | except Exception: |
| | _HAS_ROUTER = False |
| |
|
| | def set_db_choice(choice: str): |
| | st.session_state["__db_choice__"] = (choice or "prod").lower() |
| |
|
| | def current_db_choice() -> str: |
| | return st.session_state.get("__db_choice__", "prod") |
| |
|
| | def list_banks(): |
| | return ["prod", "test"] |
| |
|
| | def bank_label(choice: str) -> str: |
| | return {"prod": "Banco 1 (📗 Produção)", "test": "Banco 2 (📕 Teste)"}.get(choice, choice) |
| |
|
| | |
| | |
| | |
| | def _get_db_session(): |
| | """ |
| | Se o router tiver uma fábrica de sessão por banco, usa ela. |
| | Caso contrário, usa SessionLocal() padrão. |
| | """ |
| | try: |
| | if _HAS_ROUTER and callable(get_session_for_current_db): |
| | return get_session_for_current_db() |
| | except Exception: |
| | pass |
| | return SessionLocal() |
| |
|
| | |
| | |
| | |
| | def _mostrar_efeito_aniversario(nome: str): |
| | """Exibe imediatamente efeito e mensagem central de aniversário.""" |
| | try: |
| | st.balloons() |
| | except Exception: |
| | pass |
| |
|
| | st.markdown( |
| | f""" |
| | <div style=" |
| | display:flex;align-items:center;justify-content:center; |
| | text-align:center;margin:40px 0 20px 0;"> |
| | <div style=" |
| | font-size: 32px; font-weight: 800; color:#A020F0; |
| | background:linear-gradient(90deg,#FFF0F6,#F0E6FF); |
| | padding:16px 24px;border-radius:16px;box-shadow:0 4px 10px rgba(0,0,0,.08);"> |
| | 🎉 Feliz Aniversário, {nome}! 🎉 |
| | </div> |
| | </div> |
| | """, |
| | unsafe_allow_html=True |
| | ) |
| | st.caption("Desejamos a você muitas conquistas e bons embarques ao longo do ano! 💜") |
| |
|
| | |
| | |
| | |
| | def _autologin_if_allowed() -> bool: |
| | """ |
| | Se DISABLE_AUTH=1 estiver definido nos Secrets, |
| | entra automático (apenas para teste/homologação). |
| | """ |
| | if os.getenv("DISABLE_AUTH", "0") == "1": |
| | st.session_state.logado = True |
| | st.session_state.usuario = os.getenv("DEMO_USER", "demo") |
| | st.session_state.perfil = os.getenv("DEMO_PERFIL", "admin") |
| | st.session_state.email = os.getenv("DEMO_EMAIL", "demo@example.com") |
| | st.info("🔓 Autologin (DISABLE_AUTH=1) — apenas para teste/homologação.") |
| | return True |
| | return False |
| |
|
| | def _render_emergency_login(): |
| | """ |
| | Login emergencial (opcional), protegido por Secrets: |
| | - ALLOW_EMERGENCY_LOGIN=1 (habilita) |
| | - EMERG_USER (usuário) |
| | - EMERG_PASS_BCRYPT (hash bcrypt da senha) OU EMERG_PASS_PLAIN (apenas para teste) |
| | """ |
| | if os.getenv("ALLOW_EMERGENCY_LOGIN", "0") != "1": |
| | st.info( |
| | "Login temporariamente indisponível.\n\n" |
| | "• Para testar: defina **DISABLE_AUTH=1** em *Settings → Secrets*\n" |
| | "• Para contingência: **ALLOW_EMERGENCY_LOGIN=1**, EMERG_USER e EMERG_PASS_BCRYPT" |
| | ) |
| | return |
| |
|
| | import bcrypt |
| | st.markdown("#### Login emergencial") |
| | with st.form("emergency_login"): |
| | u = st.text_input("Usuário", value=os.getenv("EMERG_USER", "admin")) |
| | p = st.text_input("Senha", type="password") |
| | ok = st.form_submit_button("Entrar") |
| |
|
| | if ok: |
| | user_ok = (u == os.getenv("EMERG_USER", "admin")) |
| | pass_hash = (os.getenv("EMERG_PASS_BCRYPT") or "").strip() |
| | pass_plain= (os.getenv("EMERG_PASS_PLAIN") or "").strip() |
| |
|
| | pass_ok = False |
| | if pass_hash: |
| | try: |
| | pass_ok = bcrypt.checkpw(p.encode(), pass_hash.encode()) |
| | except Exception as e: |
| | st.error(f"Validação bcrypt falhou: {e}") |
| | elif pass_plain: |
| | pass_ok = (p == pass_plain) |
| | st.warning("⚠️ EMERG_PASS_PLAIN em uso. Prefira EMERG_PASS_BCRYPT (mais seguro).") |
| | else: |
| | st.error("Defina EMERG_PASS_BCRYPT (ou EMERG_PASS_PLAIN apenas para teste).") |
| |
|
| | if user_ok and pass_ok: |
| | st.session_state.logado = True |
| | st.session_state.usuario = u |
| | st.session_state.perfil = "admin" |
| | st.session_state.email = f"{u}@local" |
| | st.success("Login emergencial efetuado.") |
| | st.rerun() |
| | else: |
| | st.error("Usuário e/ou senha inválidos (emergencial).") |
| |
|
| | |
| | |
| | |
| | def login(): |
| | st.subheader("🔐 Login") |
| |
|
| | |
| | banks = list_banks() |
| | labels = [bank_label(b) for b in banks] |
| | idx_default = banks.index("prod") if "prod" in banks else 0 |
| |
|
| | banco_label_sel = st.selectbox("Usar banco:", labels, index=idx_default) |
| | db_choice = banks[labels.index(banco_label_sel)] |
| | set_db_choice(db_choice) |
| |
|
| | |
| | ambiente = current_db_choice() |
| | if ambiente == "prod": |
| | badge = "🟢 Produção" |
| | elif ambiente == "test": |
| | badge = "🔴 Teste" |
| | elif ambiente == "treinamento": |
| | badge = "🔵 Treinamento" |
| | else: |
| | badge = ambiente |
| | st.sidebar.caption(f"🗄️ Banco ativo: {badge}") |
| |
|
| | |
| | if _autologin_if_allowed(): |
| | return |
| |
|
| | |
| | usuario_input = st.text_input("Usuário") |
| | senha_input = st.text_input("Senha", type="password") |
| |
|
| | |
| | if st.button("Entrar", type="primary"): |
| | db = _get_db_session() |
| | try: |
| | usuario_db = ( |
| | db.query(Usuario) |
| | .filter(Usuario.usuario == usuario_input, Usuario.ativo == True) |
| | .first() |
| | ) |
| |
|
| | if not usuario_db or not verificar_senha(senha_input, getattr(usuario_db, "senha", "")): |
| | st.error("❌ Usuário ou senha inválidos.") |
| | |
| | try: |
| | registrar_log( |
| | usuario=usuario_input or "(vazio)", |
| | acao="Tentativa de login inválida", |
| | tabela="usuarios", |
| | ambiente=current_db_choice() |
| | ) |
| | except Exception: |
| | pass |
| | return |
| |
|
| | |
| | st.session_state.logado = True |
| | st.session_state.usuario = usuario_db.usuario |
| | st.session_state.perfil = getattr(usuario_db, "perfil", "usuario") or "usuario" |
| | st.session_state.email = getattr(usuario_db, "email", None) |
| | st.session_state.nome = getattr(usuario_db, "nome", None) |
| |
|
| | |
| | st.session_state.quiz_verificado = False |
| |
|
| | |
| | try: |
| | registrar_log( |
| | usuario=usuario_db.usuario, |
| | acao="Login realizado com sucesso", |
| | tabela="usuarios", |
| | registro_id=getattr(usuario_db, "id", None), |
| | ambiente=current_db_choice() |
| | ) |
| | except Exception: |
| | pass |
| |
|
| | |
| | try: |
| | from datetime import date as _date |
| | def _to_date_safe(val): |
| | if not val: |
| | return None |
| | if isinstance(val, _date): |
| | return val |
| | try: |
| | yy, mm, dd = map(int, str(val).split("-")) |
| | return _date(yy, mm, dd) |
| | except Exception: |
| | return None |
| |
|
| | dn = _to_date_safe(getattr(usuario_db, "data_aniversario", None)) |
| | hoje = _date.today() |
| | if dn and dn.month == hoje.month and dn.day == hoje.day: |
| | nome_exibir = st.session_state.get("nome") or st.session_state.get("usuario") or "Usuário" |
| | _mostrar_efeito_aniversario(nome_exibir) |
| | st.session_state["__show_birthday__"] = True |
| | except Exception: |
| | pass |
| |
|
| | st.success("✅ Login realizado com sucesso!") |
| | st.rerun() |
| |
|
| | finally: |
| | try: |
| | db.close() |
| | except Exception: |
| | pass |
| |
|
| | |
| | if not st.session_state.get("logado"): |
| | _render_emergency_login() |
| | `` |