diff --git a/app.py b/app.py index 55decea..afce09a 100644 --- a/app.py +++ b/app.py @@ -37,7 +37,7 @@ def login_required(f): def decorated_function(*args, **kwargs): if 'user_id' not in session: flash('Por favor, faça login para acessar esta página.', 'warning') - return redirect(url_for('login', next=request.url)) + return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function @@ -59,16 +59,35 @@ def login(): password = request.form.get("password") otp = request.form.get("otp") + # Log dos dados recebidos (sem a senha) + print(f"Tentativa de login - Username: {username}, OTP fornecido: {'Sim' if otp else 'Não'}") + user = db_session.query(Usuario).filter_by(username=username).first() - if user and user.check_password(password) and user.verify_otp(otp): - session['user_id'] = user.id # Usando a sessão do Flask - session['is_admin'] = user.is_admin - next_page = request.args.get('next') - flash('Login realizado com sucesso!', 'success') - return redirect(next_page or url_for('home')) - else: - flash('Credenciais inválidas', 'danger') + if not user: + print(f"Erro: Usuário '{username}' não encontrado") + flash('Usuário não encontrado', 'danger') + return render_template('login.html') + + if not user.check_password(password): + print(f"Erro: Senha incorreta para o usuário '{username}'") + flash('Senha incorreta', 'danger') + return render_template('login.html') + + if not user.verify_otp(otp): + print(f"Erro: Código OTP inválido para o usuário '{username}'") + print(f"OTP fornecido: {otp}") + print(f"OTP secret do usuário: {user.otp_secret}") + flash('Código OTP inválido', 'danger') + return render_template('login.html') + + # Se chegou aqui, login bem sucedido + print(f"Login bem sucedido para o usuário '{username}'") + session['user_id'] = user.id + session['is_admin'] = user.is_admin + next_page = request.args.get('next') + flash('Login realizado com sucesso!', 'success') + return redirect(next_page or url_for('home')) return render_template('login.html') @@ -84,14 +103,36 @@ def logout(): @login_required def home(): """Página inicial do sistema""" - links = [] - for rule in app.url_map.iter_rules(): - if "GET" in rule.methods and has_no_empty_params(rule): - url = url_for(rule.endpoint, **(rule.defaults or {})) - endpoint_name = 'Início' if rule.endpoint == 'home' else rule.endpoint - links.append((url, endpoint_name)) - - return render_template('home.html', links=links) + try: + links = [] + # Filtrar apenas as rotas que queremos mostrar + allowed_endpoints = { + 'listar_militantes': 'Militantes', + 'listar_cotas': 'Cotas', + 'listar_pagamentos': 'Pagamentos', + 'listar_materiais': 'Materiais', + 'listar_vendas_jornal': 'Vendas de Jornal', + 'listar_assinaturas': 'Assinaturas' + } + + for rule in app.url_map.iter_rules(): + if (rule.endpoint in allowed_endpoints and + "GET" in rule.methods and + len(rule.arguments) == 0): # Apenas rotas sem parâmetros + url = url_for(rule.endpoint) + nome = allowed_endpoints[rule.endpoint] + links.append((url, nome)) + + # Ordenar links pelo nome + links.sort(key=lambda x: x[1]) + + return render_template('home.html', links=links) + except Exception as e: + print(f"Erro na página inicial: {e}") + import traceback + traceback.print_exc() + flash('Erro ao carregar a página inicial', 'error') + return render_template('home.html', links=[]) # Rota para criar um novo militante @app.route("/militantes/novo", methods=["GET", "POST"]) diff --git a/create_admin.py b/create_admin.py index 5f34754..ee162d4 100644 --- a/create_admin.py +++ b/create_admin.py @@ -1,78 +1,61 @@ -from functions.database import Usuario, Base, engine, get_db_connection +from functions.database import init_database, Usuario, get_db_connection import qrcode import os from pathlib import Path def create_admin_user(): try: - # Criar as tabelas se não existirem - Base.metadata.create_all(engine) + # Inicializar o banco de dados + init_database() - # Obter conexão com o banco + # Obter a sessão db_session = get_db_connection() - # Verificar se já existe um admin + # Verificar se o admin foi criado admin = db_session.query(Usuario).filter_by(username="admin").first() - if not admin: - # Criar usuário admin - admin = Usuario( - username="admin", - password="admin123", - is_admin=True - ) - admin.email = "admin@example.com" + if admin: + print("\n=== Detalhes do Usuário Admin ===") + print(f"Username: admin") + print(f"Email: {admin.email}") + print(f"OTP Secret: {admin.otp_secret}") - db_session.add(admin) - db_session.commit() + # Configurar diretório para o QR Code + home = Path.home() + qr_dir = home / '.local' / 'share' / 'controles' / 'qrcodes' + qr_dir.mkdir(parents=True, exist_ok=True) - print("\n=== Usuário Admin Criado com Sucesso ===") + # Gerar QR Code + qr = qrcode.QRCode(version=1, box_size=10, border=5) + qr.add_data(admin.get_otp_uri()) + qr.make(fit=True) + + # Salvar QR Code + qr_path = qr_dir / 'admin_qr.png' + img = qr.make_image(fill_color="black", back_color="white") + img.save(str(qr_path)) + + print(f"\nQR Code salvo em: {qr_path}") + print("\nPasso a passo para configurar o OTP:") + print("1. Instale um aplicativo autenticador no seu celular") + print(" (Google Authenticator, Microsoft Authenticator, etc)") + print("2. Abra o aplicativo") + print("3. Selecione a opção para adicionar uma nova conta") + print("4. Escaneie o QR Code gerado") + print("\nOU, se preferir configuração manual:") + print(f"1. Use o segredo: {admin.otp_secret}") + print("2. Nome da conta: admin") + print("3. Tipo: Baseado em tempo (TOTP)") else: - print("\n=== Usuário Admin Encontrado ===") - - print(f"Username: admin") - print(f"Senha: admin123") - print(f"Segredo OTP: {admin.otp_secret}") - - # Gerar QR Code - qr = qrcode.QRCode(version=1, box_size=10, border=5) - qr.add_data(admin.get_otp_uri()) - qr.make(fit=True) - - # Encontrar o diretório raiz do projeto (onde está o app.py) - current_dir = Path(__file__).resolve().parent - project_root = current_dir.parent # Volta um nível para a raiz do projeto - static_dir = project_root / 'static' - - # Criar diretório static se não existir - os.makedirs(static_dir, exist_ok=True) - - # Caminho completo para o arquivo QR code - qr_path = static_dir / 'admin_qr.png' - - # Salvar QR Code como imagem - img = qr.make_image(fill_color="black", back_color="white") - img.save(str(qr_path)) - - print(f"\nQR Code salvo em: {qr_path}") - print(f"Diretório atual: {os.getcwd()}") - print(f"O arquivo existe? {os.path.exists(qr_path)}") - - print("\nPasso a passo para configurar o OTP:") - print("1. Instale um aplicativo autenticador no seu celular") - print(" (Google Authenticator, Microsoft Authenticator, etc)") - print("2. Abra o aplicativo") - print("3. Selecione a opção para adicionar uma nova conta") - print("4. Escaneie o QR Code gerado") - print("\nOU, se preferir configuração manual:") - print(f"1. Use o segredo: {admin.otp_secret}") - print("2. Nome da conta: admin") - print("3. Tipo: Baseado em tempo (TOTP)") - + print("ERRO: Falha ao criar usuário admin!") + except Exception as e: print(f"\nErro durante a execução: {e}") import traceback traceback.print_exc() + finally: + if 'db_session' in locals(): + db_session.close() if __name__ == "__main__": create_admin_user() \ No newline at end of file diff --git a/functions/database.py b/functions/database.py index c4d775d..56504d0 100644 --- a/functions/database.py +++ b/functions/database.py @@ -4,16 +4,32 @@ from sqlalchemy.ext.declarative import declarative_base from werkzeug.security import generate_password_hash, check_password_hash import pyotp import os +from pathlib import Path +from sqlalchemy.pool import NullPool + +# Configurar caminho do banco de dados +db_dir = Path.home() / '.local' / 'share' / 'controles' +db_dir.mkdir(parents=True, exist_ok=True) +db_path = db_dir / 'database.db' + +# Configurar engine com NullPool +engine = create_engine( + f'sqlite:///{db_path}', + echo=True, + poolclass=NullPool # Usar NullPool ao invés do pool padrão +) Base = declarative_base() -engine = create_engine('sqlite:///database.db', echo=True) SessionLocal = sessionmaker(bind=engine) def get_db_connection(): """ Retorna uma nova sessão do banco de dados """ - return SessionLocal() + try: + return SessionLocal() + finally: + engine.dispose() def execute_query(query, params=None): """ @@ -195,11 +211,17 @@ class Usuario(Base): self.password_hash = generate_password_hash(password) def check_password(self, password): - return check_password_hash(self.password_hash, password) + result = check_password_hash(self.password_hash, password) + print(f"Verificação de senha para {self.username}: {'sucesso' if result else 'falha'}") + return result def verify_otp(self, otp_code): totp = pyotp.TOTP(self.otp_secret) - return totp.verify(otp_code) + result = totp.verify(otp_code) + print(f"Verificação OTP para {self.username}") + print(f"Código fornecido: {otp_code}") + print(f"Resultado da verificação: {'válido' if result else 'inválido'}") + return result def get_otp_uri(self): totp = pyotp.TOTP(self.otp_secret) @@ -234,40 +256,61 @@ class RolePermissao(Base): permissao = relationship("Permissao", back_populates="roles") # Remover o banco de dados existente (se existir) -if os.path.exists('database.db'): - os.remove('database.db') +if os.path.exists(db_path): + os.remove(db_path) -# Criar todas as tabelas novamente -Base.metadata.create_all(engine) - -# Criar roles iniciais -def create_initial_data(): - session = get_db_connection() +def init_database(): + """Inicializa o banco de dados com dados básicos""" + print("Inicializando banco de dados...") + + # Criar todas as tabelas + Base.metadata.create_all(engine) + + session = SessionLocal() try: - # Criar role de admin - admin_role = Role(nome="Administrador", nivel=1) - session.add(admin_role) - session.flush() # Para obter o ID da role - - # Criar usuário admin - admin = Usuario( - username="admin", - password="admin123", - is_admin=True - ) - admin.role_id = admin_role.id - session.add(admin) - - session.commit() - print(f"Segredo OTP do admin: {admin.otp_secret}") - print("Usuário admin criado com sucesso!") + # Verificar se já existe um admin + admin = session.query(Usuario).filter_by(username="admin").first() + if not admin: + print("Criando role de administrador...") + # Criar role de admin + admin_role = session.query(Role).filter_by(nome="Administrador").first() + if not admin_role: + admin_role = Role(nome="Administrador", nivel=1) + session.add(admin_role) + session.commit() + + print("Criando usuário admin...") + # Criar usuário admin + admin = Usuario( + username="admin", + password="admin123", + is_admin=True + ) + admin.email = "admin@example.com" + admin.role_id = admin_role.id + + session.add(admin) + session.commit() + + print("=== Usuário Admin Criado ===") + print(f"Username: admin") + print(f"Senha: admin123") + print(f"Email: {admin.email}") + print(f"OTP Secret: {admin.otp_secret}") + else: + print("Usuário admin já existe") + except Exception as e: - print(f"Erro ao criar dados iniciais: {e}") + print(f"Erro na inicialização do banco: {e}") session.rollback() + raise finally: session.close() +# Inicializar o banco de dados automaticamente quando o módulo for importado +init_database() + # Executar a criação dos dados iniciais if __name__ == "__main__": - create_initial_data() \ No newline at end of file + init_database() \ No newline at end of file diff --git a/templates/home.html b/templates/home.html index 31779b9..78bbb56 100644 --- a/templates/home.html +++ b/templates/home.html @@ -3,15 +3,26 @@ {% block title %}Início{% endblock %} {% block content %} -