""" Módulo de autenticación para la aplicación Veureu. Gestiona usuarios, verificación de contraseñas y sincronización de usuarios por defecto. """ import sys import streamlit as st from datetime import datetime from database import get_user, create_user, update_user_password, get_all_users from mobile_verification import ( initialize_sms_state, render_mobile_verification_screen, get_user_permissions, show_verification_status_in_sidebar ) def log(msg: str): """Helper per logging amb timestamp""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") sys.stderr.write(f"[{timestamp}] {msg}\n") sys.stderr.flush() def verify_password(password: str, stored_password: str) -> bool: """Verifica la contraseña como texto plano.""" return password == stored_password def create_default_users_if_needed(): """Asegura que existan los usuarios por defecto y sus contraseñas esperadas (texto plano).""" log("Sincronizando usuarios por defecto...") users_to_create = [ ("verd", "verd123", "verd"), ("groc", "groc123", "groc"), ("taronja", "taronja123", "taronja"), ("blau", "blau123", "blau"), ("vermell", "vermell123", "vermell"), ] for username, password, role in users_to_create: try: row = get_user(username) if row: update_user_password(username, password) log(f"Usuario '{username}' actualizado (password reset).") else: create_user(username, password, role) log(f"Usuario '{username}' creado.") except Exception as e: log(f"Error sincronizando usuario {username}: {e}") def initialize_auth_system(db_path: str): """Inicializa el sistema de autenticación y sincroniza usuarios.""" if 'users_synced' not in st.session_state: create_default_users_if_needed() st.session_state['users_synced'] = True # Inicializar estado de verificación SMS initialize_sms_state() # Diagnóstico de base de datos if 'diag_logged' not in st.session_state: log("\n--- DIAGNÓSTICO DE BASE DE DATOS ---") log(f"Ruta de la BD en uso: {db_path}") try: all_users = get_all_users() if all_users: log("Usuarios encontrados en la BD al arrancar:") users_list = [dict(user) for user in all_users] log(str(users_list)) else: log("La tabla de usuarios está vacía.") except Exception as e: log(f"Error al intentar leer los usuarios de la BD: {e}") log("--- FIN DIAGNÓSTICO ---\n") st.session_state['diag_logged'] = True def require_login(login_form_func): """Requiere que el usuario esté autenticado.""" if not st.session_state.user: st.info("Por favor, inicia sesión para continuar.") login_form_func() st.stop() def render_login_form(): """Renderiza el formulario de login con logs de depuración.""" st.subheader("Inici de sessió") username = st.text_input("Usuari") password = st.text_input("Contrasenya", type="password") if st.button("Entrar", type="primary"): row = get_user(username) # Logs de depuración log("\n--- INTENTO DE LOGIN ---") log(f"Usuario introducido: '{username}'") log(f"Contraseña introducida: {'Sí' if password else 'No'}") if row: log(f"Usuario encontrado en BD: '{row['username']}'") stored_pw = (row["password_hash"] or "") log(f"Password almacenado (longitud): {len(stored_pw)}") is_valid = verify_password(password, stored_pw) log(f"Resultado de verify_password: {is_valid}") else: log("Usuario no encontrado en la BD.") is_valid = False log("--- FIN INTENTO DE LOGIN ---\n") if is_valid: st.session_state.user = { "id": row["id"], "username": row["username"], "role": row["role"] } st.success(f"Benvingut/da, {row['username']}") st.rerun() else: st.error("Credencials invàlides") def render_sidebar(): """Renderiza la barra lateral con información de usuario y navegación.""" role = st.session_state.user["role"] if st.session_state.user else None with st.sidebar: st.title("Veureu") if st.session_state.user: st.write(f"Usuari: **{st.session_state.user['username']}** (rol: {st.session_state.user['role']})") # Mostrar estado de verificación SMS show_verification_status_in_sidebar() if st.button("Tancar sessió"): st.session_state.user = None st.session_state.sms_verified = None st.rerun() if st.session_state.user: # Obtener permisos del usuario permissions = get_user_permissions( role, st.session_state.get('sms_verified') ) # Construir opciones de navegación según permisos page_options = [] if permissions["analizar"]: page_options.append("Analitzar video-transcripcions") if permissions["procesar_videos"]: page_options.append("Processar vídeo nou") if permissions["estadisticas"]: page_options.append("Estadístiques") if permissions["validar"]: page_options.append("Validació") # Si no hay opciones disponibles, mostrar solo análisis if not page_options: page_options = ["Analitzar video-transcripcions"] page = st.radio( "Navegació", page_options, index=0 ) else: page = None return page, role