Roudrigus commited on
Commit
ccb6818
·
verified ·
1 Parent(s): aad32ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -79
app.py CHANGED
@@ -20,10 +20,8 @@ load_dotenv()
20
  # Utilitários de robustez / compatibilidade
21
  # --------------------------------------------------------------------------------------
22
  def _module_stub(name: str, hint: str = ""):
23
- """
24
- Retorna um objeto com .main() e .pagina() que exibe aviso amigável
25
- quando o módulo não puder ser importado/usar no ambiente atual.
26
- """
27
  class _Stub:
28
  def __init__(self, _name, _hint):
29
  self.__name = _name
@@ -35,27 +33,19 @@ def _module_stub(name: str, hint: str = ""):
35
  return _Stub(name, hint)
36
 
37
  def _try_import(module_name: str, on_fail_hint: str = ""):
38
- """
39
- Import "seguro": caso falhe, retorna stub que não derruba o app.
40
- """
41
  try:
42
  return importlib.import_module(module_name)
43
  except Exception as e:
44
  return _module_stub(module_name, f"{on_fail_hint}\n\n**Detalhe técnico:** {e}")
45
 
46
  def _ensure_db_case_alias(expected_names=("load.db", "Load.db", "LOAD.DB")):
47
- """
48
- Se existir um .db com caixa diferente do usado pelo código, cria uma CÓPIA
49
- com o nome esperado, evitando erro de case-sensitive no Linux.
50
- - Preferência: se 'load.db' não existir, mas houver 'Load.db', gera 'load.db'.
51
- """
52
  base = os.path.abspath(os.getcwd())
53
  candidates = [os.path.join(base, n) for n in expected_names]
54
- # Se já existir um 'load.db', não faz nada
55
  lower = os.path.join(base, "load.db")
56
  if os.path.exists(lower):
57
  return lower
58
- # Procura qualquer outro nome por case diferente e copia para 'load.db'
59
  for path in candidates:
60
  if os.path.exists(path):
61
  try:
@@ -64,14 +54,13 @@ def _ensure_db_case_alias(expected_names=("load.db", "Load.db", "LOAD.DB")):
64
  return lower
65
  except Exception:
66
  pass
67
- # Não encontrou nada; apenas retorna o que seria o caminho padrão
68
  return lower
69
 
70
  # Ajuste preventivo do case do banco (caso módulos internos usem 'load.db')
71
  _DB_ALIAS = _ensure_db_case_alias()
72
 
73
  # --------------------------------------------------------------------------------------
74
- # Imports internos que DEVEM existir (são base do app)
75
  # --------------------------------------------------------------------------------------
76
  from utils_operacao import obter_grupos_disponiveis, obter_modulos_para_grupo
77
  from utils_info import INFO_CONTEUDO, INFO_MODULOS, INFO_MAP_PAGINA_ID
@@ -83,11 +72,8 @@ from banco import engine, Base, SessionLocal
83
  from models import QuizPontuacao, IOIRunSugestao, AvisoGlobal
84
 
85
  # --------------------------------------------------------------------------------------
86
- # Imports de páginas/módulos com fallback (não derrubam o app se faltar algo)
87
  # --------------------------------------------------------------------------------------
88
- # Observação: alguns módulos podem depender de libs não disponíveis no Linux;
89
- # por isso usamos _try_import e stubs.
90
-
91
  formulario = _try_import("formulario")
92
  consulta = _try_import("consulta")
93
  relatorio = _try_import("relatorio")
@@ -107,7 +93,7 @@ db_admin = _try_import("db_admin")
107
  db_monitor = _try_import("db_monitor")
108
  operacao = _try_import("operacao")
109
  db_export_import = _try_import("db_export_import")
110
- resposta = _try_import("resposta") # 📬 Admin: Caixa de Entrada IOI‑RUN
111
  repositorio_load = _try_import("repositorio_load")
112
  produtividade_especialista = _try_import("Produtividade_Especialista")
113
  rnc = _try_import("rnc")
@@ -329,7 +315,7 @@ def _mark_session_inactive() -> None:
329
  except Exception: pass
330
 
331
  # --------------------------------------------------------------------------------------
332
- # Aviso Global
333
  # --------------------------------------------------------------------------------------
334
  def _sanitize_largura(largura_raw: str) -> str:
335
  val = (largura_raw or "").strip()
@@ -385,7 +371,7 @@ def _render_aviso_global_topbar():
385
  altura = 52 # px
386
  st.markdown(
387
  f"""
388
- <style>
389
  .stApp::before,
390
  header[data-testid="stHeader"],
391
  [data-testid="stToolbar"],
@@ -442,13 +428,13 @@ header[data-testid="stHeader"],
442
  }}
443
  [data-testid="stAppViewContainer"] {{ padding-top: 52px !important; }}
444
  }}
445
- </style>
446
 
447
- <div class="ag-topbar-wrap">
448
- <div class="ag-topbar-inner {'ag-topbar-marquee' if efeito=='marquee' else ''}">
449
- <span>{getattr(aviso, 'mensagem', '')}</span>
450
- </div>
451
- </div>
452
  """,
453
  unsafe_allow_html=True
454
  )
@@ -477,7 +463,7 @@ def _show_birthday_banner_if_needed():
477
  st.session_state["__show_birthday__"] = False
478
  st.markdown(
479
  """
480
- <style>
481
  .confetti-wrapper { position: relative; width: 100%; height: 0; }
482
  .confetti-area { position: fixed; top: 0; left: 0; width: 100%; height: 100%;
483
  pointer-events: none; z-index: 9999; }
@@ -499,17 +485,17 @@ def _show_birthday_banner_if_needed():
499
  .confetti:nth-child(10) { left: 76%; animation-duration: 4.2s; }
500
  .confetti:nth-child(11) { left: 84%; animation-duration: 3.6s; }
501
  .confetti:nth-child(12) { left: 92%; animation-duration: 4.0s; }
502
- </style>
503
- <div class="confetti-wrapper">
504
- <div class="confetti-area">
505
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
506
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
507
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
508
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
509
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
510
- <div class="confetti">🎊</div><div class="confetti">🎉</div>
511
- </div>
512
- </div>
513
  """,
514
  unsafe_allow_html=True
515
  )
@@ -517,24 +503,24 @@ def _show_birthday_banner_if_needed():
517
  nome = st.session_state.get("nome") or st.session_state.get("usuario") or "Usuário"
518
  st.markdown(
519
  f"""
520
- <div style="display:flex;justify-content:center;align-items:center;text-align:center;width:100%;margin:40px 0;">
521
- <div style="font-size: 36px; font-weight: 800; color:#A020F0;
522
- background:linear-gradient(90deg,#FFF0F6,#F0E6FF);
523
- padding:20px 30px; border-radius:16px; box-shadow:0 4px 10px rgba(0,0,0,.08);">
524
- 🎉 Feliz Aniversário, {nome}! 🎉
525
- </div>
526
- </div>
527
  """,
528
  unsafe_allow_html=True
529
  )
530
  COR_FRASE = "#0d6efd"
531
  st.markdown(
532
  f"""
533
- <div style="display:flex;justify-content:center;align-items:center;text-align:center;width:100%;margin-top:10px;">
534
- <div style="font-size: 20px; font-weight: 500; color:{COR_FRASE}; padding:10px;">
535
- Desejamos a você muitas conquistas e bons embarques ao longo do ano! 💜
536
- </div>
537
- </div>
538
  """,
539
  unsafe_allow_html=True
540
  )
@@ -567,11 +553,11 @@ def main():
567
  online_now = 0
568
  st.sidebar.markdown(
569
  f"""
570
- <div style="padding:8px 10px;margin-top:6px;margin-bottom:6px;border-radius:8px;
571
- background:#1e293b; color:#e2e8f0; border:1px solid #334155;">
572
- <span style="font-size:13px;">🟢 Online (últimos {_SESS_TTL_MIN} min)</span><br>
573
- <span style="font-size:22px;font-weight:800;">{online_now}</span>
574
- </div>
575
  """,
576
  unsafe_allow_html=True
577
  )
@@ -644,6 +630,7 @@ def main():
644
  banco_lbl = bank_label(current_db_choice()) if _HAS_ROUTER else (
645
  "🟢 Produção" if current_db_choice() == "prod" else "🔴 Teste"
646
  )
 
647
  st.sidebar.caption(f"🗄️ Banco ativo: {banco_lbl}")
648
  except Exception:
649
  pass
@@ -680,7 +667,12 @@ def main():
680
  )
681
 
682
  with st.sidebar.expander("🔧 Diagnóstico do menu", expanded=False):
683
- st.caption(f"Perfil: **{st.session_state.get('perfil', '—')}** | Grupo: **{grupo_escolhido}** | Busca: **{termo_busca or '∅'}** | Ambiente: **{ambiente_atual}**")
 
 
 
 
 
684
  try:
685
  mods_dbg = [{"id": mid, "label": lbl} for mid, lbl in (opcoes or [])]
686
  except Exception:
@@ -867,28 +859,13 @@ Selecione o módulo abaixo ou navegue pelo menu — o conteúdo ajusta automatic
867
  if __name__ == "__main__":
868
  main()
869
 
870
- # Rodapé (visível quando logado)
871
  if st.session_state.get("logado") and st.session_state.get("email"):
872
- st.sidebar.markdown(
873
- f"""
874
- <div style="display:inline-flex;align-items:center;gap:8px; padding:4px 8px;border-radius:8px;
875
- background:#e7f1ff;color:#0d6efd;font-size:13px;line-height:1.2;">
876
- <span style="font-size:16px;">👤</span>
877
- <span>{st.session_state.email}</span>
878
- </div>
879
- """,
880
- unsafe_allow_html=True
881
- )
882
 
883
- st.sidebar.markdown(
884
- """
885
- <hr style="margin-top: 10px; margin-bottom: 6px;">
886
- <p style="font-size: 12px; color: #6c757d;">
887
- Versão: <strong>1.0.0</strong> • Desenvolvedor: <strong>Rodrigo Silva - Ideiasystem | 2026</strong>
888
- </p>
889
- """,
890
- unsafe_allow_html=True
891
- )
892
 
893
 
894
 
 
20
  # Utilitários de robustez / compatibilidade
21
  # --------------------------------------------------------------------------------------
22
  def _module_stub(name: str, hint: str = ""):
23
+ """Stub com .main() e .pagina() que exibe aviso amigável quando o módulo
24
+ não puder ser importado/usado no ambiente atual."""
 
 
25
  class _Stub:
26
  def __init__(self, _name, _hint):
27
  self.__name = _name
 
33
  return _Stub(name, hint)
34
 
35
  def _try_import(module_name: str, on_fail_hint: str = ""):
36
+ """Import 'seguro': caso falhe, retorna stub que não derruba o app."""
 
 
37
  try:
38
  return importlib.import_module(module_name)
39
  except Exception as e:
40
  return _module_stub(module_name, f"{on_fail_hint}\n\n**Detalhe técnico:** {e}")
41
 
42
  def _ensure_db_case_alias(expected_names=("load.db", "Load.db", "LOAD.DB")):
43
+ """Se existir um .db com caixa diferente, cria CÓPIA 'load.db' (Linux é case-sensitive)."""
 
 
 
 
44
  base = os.path.abspath(os.getcwd())
45
  candidates = [os.path.join(base, n) for n in expected_names]
 
46
  lower = os.path.join(base, "load.db")
47
  if os.path.exists(lower):
48
  return lower
 
49
  for path in candidates:
50
  if os.path.exists(path):
51
  try:
 
54
  return lower
55
  except Exception:
56
  pass
 
57
  return lower
58
 
59
  # Ajuste preventivo do case do banco (caso módulos internos usem 'load.db')
60
  _DB_ALIAS = _ensure_db_case_alias()
61
 
62
  # --------------------------------------------------------------------------------------
63
+ # Imports internos essenciais
64
  # --------------------------------------------------------------------------------------
65
  from utils_operacao import obter_grupos_disponiveis, obter_modulos_para_grupo
66
  from utils_info import INFO_CONTEUDO, INFO_MODULOS, INFO_MAP_PAGINA_ID
 
72
  from models import QuizPontuacao, IOIRunSugestao, AvisoGlobal
73
 
74
  # --------------------------------------------------------------------------------------
75
+ # Imports de páginas/módulos com fallback
76
  # --------------------------------------------------------------------------------------
 
 
 
77
  formulario = _try_import("formulario")
78
  consulta = _try_import("consulta")
79
  relatorio = _try_import("relatorio")
 
93
  db_monitor = _try_import("db_monitor")
94
  operacao = _try_import("operacao")
95
  db_export_import = _try_import("db_export_import")
96
+ resposta = _try_import("resposta") # 📬 Admin
97
  repositorio_load = _try_import("repositorio_load")
98
  produtividade_especialista = _try_import("Produtividade_Especialista")
99
  rnc = _try_import("rnc")
 
315
  except Exception: pass
316
 
317
  # --------------------------------------------------------------------------------------
318
+ # Aviso Global (banner superior)
319
  # --------------------------------------------------------------------------------------
320
  def _sanitize_largura(largura_raw: str) -> str:
321
  val = (largura_raw or "").strip()
 
371
  altura = 52 # px
372
  st.markdown(
373
  f"""
374
+ <style>
375
  .stApp::before,
376
  header[data-testid="stHeader"],
377
  [data-testid="stToolbar"],
 
428
  }}
429
  [data-testid="stAppViewContainer"] {{ padding-top: 52px !important; }}
430
  }}
431
+ </style>
432
 
433
+ <div class="ag-topbar-wrap">
434
+ <div class="ag-topbar-inner {'ag-topbar-marquee' if efeito=='marquee' else ''}">
435
+ <span>{getattr(aviso, 'mensagem', '')}</span>
436
+ </div>
437
+ </div>
438
  """,
439
  unsafe_allow_html=True
440
  )
 
463
  st.session_state["__show_birthday__"] = False
464
  st.markdown(
465
  """
466
+ <style>
467
  .confetti-wrapper { position: relative; width: 100%; height: 0; }
468
  .confetti-area { position: fixed; top: 0; left: 0; width: 100%; height: 100%;
469
  pointer-events: none; z-index: 9999; }
 
485
  .confetti:nth-child(10) { left: 76%; animation-duration: 4.2s; }
486
  .confetti:nth-child(11) { left: 84%; animation-duration: 3.6s; }
487
  .confetti:nth-child(12) { left: 92%; animation-duration: 4.0s; }
488
+ </style>
489
+ <div class="confetti-wrapper">
490
+ <div class="confetti-area">
491
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
492
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
493
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
494
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
495
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
496
+ <div class="confetti">🎊</div><div class="confetti">🎉</div>
497
+ </div>
498
+ </div>
499
  """,
500
  unsafe_allow_html=True
501
  )
 
503
  nome = st.session_state.get("nome") or st.session_state.get("usuario") or "Usuário"
504
  st.markdown(
505
  f"""
506
+ <div style="display:flex;justify-content:center;align-items:center;text-align:center;width:100%;margin:40px 0;">
507
+ <div style="font-size: 36px; font-weight: 800; color:#A020F0;
508
+ background:linear-gradient(90deg,#FFF0F6,#F0E6FF);
509
+ padding:20px 30px; border-radius:16px; box-shadow:0 4px 10px rgba(0,0,0,.08);">
510
+ 🎉 Feliz Aniversário, {nome}! 🎉
511
+ </div>
512
+ </div>
513
  """,
514
  unsafe_allow_html=True
515
  )
516
  COR_FRASE = "#0d6efd"
517
  st.markdown(
518
  f"""
519
+ <div style="display:flex;justify-content:center;align-items:center;text-align:center;width:100%;margin-top:10px;">
520
+ <div style="font-size: 20px; font-weight: 500; color:{COR_FRASE}; padding:10px;">
521
+ Desejamos a você muitas conquistas e bons embarques ao longo do ano! 💜
522
+ </div>
523
+ </div>
524
  """,
525
  unsafe_allow_html=True
526
  )
 
553
  online_now = 0
554
  st.sidebar.markdown(
555
  f"""
556
+ <div style="padding:8px 10px;margin-top:6px;margin-bottom:6px;border-radius:8px;
557
+ background:#1e293b; color:#e2e8f0; border:1px solid #334155;">
558
+ <span style="font-size:13px;">🟢 Online (últimos {_SESS_TTL_MIN} min)</span><br>
559
+ <span style="font-size:22px;font-weight:800;">{online_now}</span>
560
+ </div>
561
  """,
562
  unsafe_allow_html=True
563
  )
 
630
  banco_lbl = bank_label(current_db_choice()) if _HAS_ROUTER else (
631
  "🟢 Produção" if current_db_choice() == "prod" else "🔴 Teste"
632
  )
633
+ # 👉 Mostra exatamente como você pediu:
634
  st.sidebar.caption(f"🗄️ Banco ativo: {banco_lbl}")
635
  except Exception:
636
  pass
 
667
  )
668
 
669
  with st.sidebar.expander("🔧 Diagnóstico do menu", expanded=False):
670
+ st.caption(
671
+ f"Perfil: **{st.session_state.get('perfil', '—')}** | "
672
+ f"Grupo: **{grupo_escolhido}** | "
673
+ f"Busca: **{termo_busca or '∅'}** | "
674
+ f"Ambiente: **{ambiente_atual}**"
675
+ )
676
  try:
677
  mods_dbg = [{"id": mid, "label": lbl} for mid, lbl in (opcoes or [])]
678
  except Exception:
 
859
  if __name__ == "__main__":
860
  main()
861
 
862
+ # ------------------------- Rodapé do sidebar (sem HTML bruto) -------------------------
863
  if st.session_state.get("logado") and st.session_state.get("email"):
864
+ st.sidebar.markdown(f"**👤 {st.session_state.email}**")
 
 
 
 
 
 
 
 
 
865
 
866
+ # ➜ Substitui <hr> por divisor nativo e <p> por Markdown simples
867
+ st.sidebar.divider()
868
+ st.sidebar.markdown("Versão: **1.0.0** • Desenvolvedor: **Rodrigo Silva - Ideiasystem | 2026**")
 
 
 
 
 
 
869
 
870
 
871