Login funcionando
This commit is contained in:
75
app.py
75
app.py
@@ -37,7 +37,7 @@ def login_required(f):
|
|||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
if 'user_id' not in session:
|
if 'user_id' not in session:
|
||||||
flash('Por favor, faça login para acessar esta página.', 'warning')
|
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 f(*args, **kwargs)
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
@@ -59,16 +59,35 @@ def login():
|
|||||||
password = request.form.get("password")
|
password = request.form.get("password")
|
||||||
otp = request.form.get("otp")
|
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()
|
user = db_session.query(Usuario).filter_by(username=username).first()
|
||||||
|
|
||||||
if user and user.check_password(password) and user.verify_otp(otp):
|
if not user:
|
||||||
session['user_id'] = user.id # Usando a sessão do Flask
|
print(f"Erro: Usuário '{username}' não encontrado")
|
||||||
session['is_admin'] = user.is_admin
|
flash('Usuário não encontrado', 'danger')
|
||||||
next_page = request.args.get('next')
|
return render_template('login.html')
|
||||||
flash('Login realizado com sucesso!', 'success')
|
|
||||||
return redirect(next_page or url_for('home'))
|
if not user.check_password(password):
|
||||||
else:
|
print(f"Erro: Senha incorreta para o usuário '{username}'")
|
||||||
flash('Credenciais inválidas', 'danger')
|
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')
|
return render_template('login.html')
|
||||||
|
|
||||||
@@ -84,14 +103,36 @@ def logout():
|
|||||||
@login_required
|
@login_required
|
||||||
def home():
|
def home():
|
||||||
"""Página inicial do sistema"""
|
"""Página inicial do sistema"""
|
||||||
links = []
|
try:
|
||||||
for rule in app.url_map.iter_rules():
|
links = []
|
||||||
if "GET" in rule.methods and has_no_empty_params(rule):
|
# Filtrar apenas as rotas que queremos mostrar
|
||||||
url = url_for(rule.endpoint, **(rule.defaults or {}))
|
allowed_endpoints = {
|
||||||
endpoint_name = 'Início' if rule.endpoint == 'home' else rule.endpoint
|
'listar_militantes': 'Militantes',
|
||||||
links.append((url, endpoint_name))
|
'listar_cotas': 'Cotas',
|
||||||
|
'listar_pagamentos': 'Pagamentos',
|
||||||
return render_template('home.html', links=links)
|
'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
|
# Rota para criar um novo militante
|
||||||
@app.route("/militantes/novo", methods=["GET", "POST"])
|
@app.route("/militantes/novo", methods=["GET", "POST"])
|
||||||
|
|||||||
@@ -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 qrcode
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
def create_admin_user():
|
def create_admin_user():
|
||||||
try:
|
try:
|
||||||
# Criar as tabelas se não existirem
|
# Inicializar o banco de dados
|
||||||
Base.metadata.create_all(engine)
|
init_database()
|
||||||
|
|
||||||
# Obter conexão com o banco
|
# Obter a sessão
|
||||||
db_session = get_db_connection()
|
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()
|
admin = db_session.query(Usuario).filter_by(username="admin").first()
|
||||||
|
|
||||||
if not admin:
|
if admin:
|
||||||
# Criar usuário admin
|
print("\n=== Detalhes do Usuário Admin ===")
|
||||||
admin = Usuario(
|
print(f"Username: admin")
|
||||||
username="admin",
|
print(f"Email: {admin.email}")
|
||||||
password="admin123",
|
print(f"OTP Secret: {admin.otp_secret}")
|
||||||
is_admin=True
|
|
||||||
)
|
|
||||||
admin.email = "admin@example.com"
|
|
||||||
|
|
||||||
db_session.add(admin)
|
# Configurar diretório para o QR Code
|
||||||
db_session.commit()
|
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:
|
else:
|
||||||
print("\n=== Usuário Admin Encontrado ===")
|
print("ERRO: Falha ao criar usuário admin!")
|
||||||
|
|
||||||
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)")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\nErro durante a execução: {e}")
|
print(f"\nErro durante a execução: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
if 'db_session' in locals():
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
create_admin_user()
|
create_admin_user()
|
||||||
@@ -4,16 +4,32 @@ from sqlalchemy.ext.declarative import declarative_base
|
|||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
import pyotp
|
import pyotp
|
||||||
import os
|
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()
|
Base = declarative_base()
|
||||||
engine = create_engine('sqlite:///database.db', echo=True)
|
|
||||||
SessionLocal = sessionmaker(bind=engine)
|
SessionLocal = sessionmaker(bind=engine)
|
||||||
|
|
||||||
def get_db_connection():
|
def get_db_connection():
|
||||||
"""
|
"""
|
||||||
Retorna uma nova sessão do banco de dados
|
Retorna uma nova sessão do banco de dados
|
||||||
"""
|
"""
|
||||||
return SessionLocal()
|
try:
|
||||||
|
return SessionLocal()
|
||||||
|
finally:
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
def execute_query(query, params=None):
|
def execute_query(query, params=None):
|
||||||
"""
|
"""
|
||||||
@@ -195,11 +211,17 @@ class Usuario(Base):
|
|||||||
self.password_hash = generate_password_hash(password)
|
self.password_hash = generate_password_hash(password)
|
||||||
|
|
||||||
def check_password(self, 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):
|
def verify_otp(self, otp_code):
|
||||||
totp = pyotp.TOTP(self.otp_secret)
|
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):
|
def get_otp_uri(self):
|
||||||
totp = pyotp.TOTP(self.otp_secret)
|
totp = pyotp.TOTP(self.otp_secret)
|
||||||
@@ -234,40 +256,61 @@ class RolePermissao(Base):
|
|||||||
permissao = relationship("Permissao", back_populates="roles")
|
permissao = relationship("Permissao", back_populates="roles")
|
||||||
|
|
||||||
# Remover o banco de dados existente (se existir)
|
# Remover o banco de dados existente (se existir)
|
||||||
if os.path.exists('database.db'):
|
if os.path.exists(db_path):
|
||||||
os.remove('database.db')
|
os.remove(db_path)
|
||||||
|
|
||||||
# Criar todas as tabelas novamente
|
def init_database():
|
||||||
Base.metadata.create_all(engine)
|
"""Inicializa o banco de dados com dados básicos"""
|
||||||
|
print("Inicializando banco de dados...")
|
||||||
# Criar roles iniciais
|
|
||||||
def create_initial_data():
|
# Criar todas as tabelas
|
||||||
session = get_db_connection()
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
|
session = SessionLocal()
|
||||||
try:
|
try:
|
||||||
# Criar role de admin
|
# Verificar se já existe um admin
|
||||||
admin_role = Role(nome="Administrador", nivel=1)
|
admin = session.query(Usuario).filter_by(username="admin").first()
|
||||||
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!")
|
|
||||||
|
|
||||||
|
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:
|
except Exception as e:
|
||||||
print(f"Erro ao criar dados iniciais: {e}")
|
print(f"Erro na inicialização do banco: {e}")
|
||||||
session.rollback()
|
session.rollback()
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
# Inicializar o banco de dados automaticamente quando o módulo for importado
|
||||||
|
init_database()
|
||||||
|
|
||||||
# Executar a criação dos dados iniciais
|
# Executar a criação dos dados iniciais
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
create_initial_data()
|
init_database()
|
||||||
@@ -3,15 +3,26 @@
|
|||||||
{% block title %}Início{% endblock %}
|
{% block title %}Início{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="container">
|
||||||
<div class="col-md-12">
|
<div class="row">
|
||||||
<h2>Menu do Sistema</h2>
|
<div class="col-md-8 offset-md-2">
|
||||||
<div class="list-group">
|
<h2 class="mb-4">Menu do Sistema</h2>
|
||||||
{% for url, endpoint in links %}
|
|
||||||
<a href="{{ url }}" class="list-group-item list-group-item-action">
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{{ endpoint|replace('_', ' ')|title }}
|
{% if messages %}
|
||||||
</a>
|
{% for category, message in messages %}
|
||||||
{% endfor %}
|
<div class="alert alert-{{ category }}">{{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<div class="list-group">
|
||||||
|
{% for url, nome in links %}
|
||||||
|
<a href="{{ url }}" class="list-group-item list-group-item-action">
|
||||||
|
{{ nome }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,7 +14,13 @@
|
|||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for category, message in messages %}
|
{% for category, message in messages %}
|
||||||
<div class="alert alert-{{ category }}">{{ message }}</div>
|
<div class="alert alert-{{ category }}">
|
||||||
|
{{ message }}
|
||||||
|
{% if category == 'danger' %}
|
||||||
|
<br>
|
||||||
|
<small>Se o problema persistir, contate o administrador.</small>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@@ -22,7 +28,8 @@
|
|||||||
<form method="POST">
|
<form method="POST">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" class="form-label">Usuário</label>
|
<label for="username" class="form-label">Usuário</label>
|
||||||
<input type="text" class="form-control" id="username" name="username" required>
|
<input type="text" class="form-control" id="username" name="username" required
|
||||||
|
value="{{ request.form.username }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label">Senha</label>
|
<label for="password" class="form-label">Senha</label>
|
||||||
@@ -30,7 +37,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="otp" class="form-label">Código OTP</label>
|
<label for="otp" class="form-label">Código OTP</label>
|
||||||
<input type="text" class="form-control" id="otp" name="otp" required>
|
<input type="text" class="form-control" id="otp" name="otp" required
|
||||||
|
pattern="[0-9]{6}" title="Digite o código de 6 dígitos">
|
||||||
<small class="form-text text-muted">Digite o código de 6 dígitos do seu aplicativo autenticador</small>
|
<small class="form-text text-muted">Digite o código de 6 dígitos do seu aplicativo autenticador</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-grid">
|
<div class="d-grid">
|
||||||
|
|||||||
Reference in New Issue
Block a user