Update app.py
Browse files
app.py
CHANGED
|
@@ -639,6 +639,102 @@ def main():
|
|
| 639 |
if st.session_state.get("__auth_diag__"):
|
| 640 |
_render_auth_diag_panel()
|
| 641 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 642 |
# 🔄 Botão de Recarregar (mantém a sessão ativa) + ⏱️ Controle do intervalo
|
| 643 |
st.sidebar.markdown("---")
|
| 644 |
col_reload, col_interval = st.sidebar.columns([1, 1])
|
|
|
|
| 639 |
if st.session_state.get("__auth_diag__"):
|
| 640 |
_render_auth_diag_panel()
|
| 641 |
|
| 642 |
+
# ============================
|
| 643 |
+
# 🔬 Diagnóstico profundo do banco (somente Admin + painel ativo)
|
| 644 |
+
# ============================
|
| 645 |
+
from sqlalchemy import inspect # import local para evitar custo desnecessário
|
| 646 |
+
with st.sidebar.expander("🧪 Diagnóstico Profundo do Banco", expanded=False):
|
| 647 |
+
db = _get_db_session()
|
| 648 |
+
try:
|
| 649 |
+
eng = db.bind
|
| 650 |
+
st.caption(f"Engine URL: {eng.url}")
|
| 651 |
+
|
| 652 |
+
# 1) SELECT 1
|
| 653 |
+
try:
|
| 654 |
+
db.execute(text("SELECT 1"))
|
| 655 |
+
st.success("SELECT 1 OK")
|
| 656 |
+
except Exception as e:
|
| 657 |
+
st.error(f"SELECT 1 falhou: {e}")
|
| 658 |
+
|
| 659 |
+
# 2) Tabelas registradas
|
| 660 |
+
insp = inspect(eng)
|
| 661 |
+
tables = insp.get_table_names()
|
| 662 |
+
st.write("Tabelas:", tables)
|
| 663 |
+
|
| 664 |
+
# 3) Detectar tabela de usuários
|
| 665 |
+
user_tables_candidates = ["usuarios", "usuario", "Usuario", "users", "auth_user"]
|
| 666 |
+
target_table = next((t for t in user_tables_candidates if t in tables), None)
|
| 667 |
+
if not target_table:
|
| 668 |
+
st.warning("Tabela de usuários não encontrada. Verifique nomes e migrations.")
|
| 669 |
+
else:
|
| 670 |
+
st.write(f"Usando tabela: **{target_table}**")
|
| 671 |
+
|
| 672 |
+
# 4) Colunas
|
| 673 |
+
cols = [c["name"] for c in insp.get_columns(target_table)]
|
| 674 |
+
st.write("Colunas:", cols)
|
| 675 |
+
|
| 676 |
+
# 5) Contagem
|
| 677 |
+
try:
|
| 678 |
+
cnt = db.execute(text(f"SELECT COUNT(*) FROM {target_table}")).fetchone()[0]
|
| 679 |
+
st.write("Quantidade de registros:", cnt)
|
| 680 |
+
except Exception as e:
|
| 681 |
+
st.error(f"COUNT(*) falhou: {e}")
|
| 682 |
+
|
| 683 |
+
# 6) Amostra de usuários (sem senhas)
|
| 684 |
+
try:
|
| 685 |
+
# tenta nomes comuns de colunas
|
| 686 |
+
sel_cols = [c for c in ["usuario", "email", "perfil", "nome"] if c in cols]
|
| 687 |
+
sel_expr = ", ".join(sel_cols) if sel_cols else "*"
|
| 688 |
+
amostra = db.execute(text(f"SELECT {sel_expr} FROM {target_table} LIMIT 5"))
|
| 689 |
+
rows = [dict(r._mapping) for r in amostra]
|
| 690 |
+
st.write("Amostra:", rows)
|
| 691 |
+
except Exception as e:
|
| 692 |
+
st.error(f"Amostra falhou: {e}")
|
| 693 |
+
|
| 694 |
+
# 7) Teste de bcrypt (não grava nada)
|
| 695 |
+
import bcrypt
|
| 696 |
+
st.markdown("---")
|
| 697 |
+
st.caption("Teste de verificação bcrypt (não grava nada)")
|
| 698 |
+
test_user = st.text_input("Usuário para testar hash", "", key="__bcrypt_user__")
|
| 699 |
+
test_pass = st.text_input("Senha para testar hash", "", type="password", key="__bcrypt_pass__")
|
| 700 |
+
|
| 701 |
+
if st.button("Testar bcrypt com este usuário", key="__btn_bcrypt_test__"):
|
| 702 |
+
try:
|
| 703 |
+
# detectar nome da coluna de senha
|
| 704 |
+
pass_cols = [c for c in ["senha_hash", "password_hash", "senha", "hash"] if c in cols]
|
| 705 |
+
user_cols = [c for c in ["usuario", "username", "login"] if c in cols]
|
| 706 |
+
if not pass_cols or not user_cols:
|
| 707 |
+
st.error("Não encontrei colunas de senha/usuário na tabela.")
|
| 708 |
+
else:
|
| 709 |
+
c_pass = pass_cols[0]
|
| 710 |
+
c_user = user_cols[0]
|
| 711 |
+
res = db.execute(
|
| 712 |
+
text(f"SELECT {c_user} AS u, {c_pass} AS h FROM {target_table} WHERE {c_user} = :u LIMIT 1"),
|
| 713 |
+
{"u": test_user.strip()}
|
| 714 |
+
).fetchone()
|
| 715 |
+
if not res:
|
| 716 |
+
st.error("Usuário não encontrado na tabela.")
|
| 717 |
+
else:
|
| 718 |
+
senha_hash = res._mapping.get("h")
|
| 719 |
+
if not senha_hash:
|
| 720 |
+
st.error(f"Coluna '{c_pass}' vazia/nula — login normal não vai entrar.")
|
| 721 |
+
else:
|
| 722 |
+
try:
|
| 723 |
+
ok = bcrypt.checkpw(test_pass.encode("utf-8"), str(senha_hash).encode("utf-8"))
|
| 724 |
+
st.success(f"bcrypt.checkpw = {ok}")
|
| 725 |
+
if not ok:
|
| 726 |
+
st.info("Se a senha no banco não for bcrypt, gere um hash e atualize o registro.")
|
| 727 |
+
except Exception as e:
|
| 728 |
+
st.error(f"Falha no bcrypt: {e}")
|
| 729 |
+
st.info("Um hash válido geralmente começa com '$2a$' ou '$2b$' e tem 60 caracteres.")
|
| 730 |
+
except Exception as e:
|
| 731 |
+
st.error(f"Erro no teste: {e}")
|
| 732 |
+
finally:
|
| 733 |
+
try:
|
| 734 |
+
db.close()
|
| 735 |
+
except Exception:
|
| 736 |
+
pass
|
| 737 |
+
|
| 738 |
# 🔄 Botão de Recarregar (mantém a sessão ativa) + ⏱️ Controle do intervalo
|
| 739 |
st.sidebar.markdown("---")
|
| 740 |
col_reload, col_interval = st.sidebar.columns([1, 1])
|