from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey from sqlalchemy.orm import relationship, backref from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime, timedelta from flask_login import UserMixin import pyotp from models.entities.base import Base from models.entities.militante import Militante class TipoUsuario(enum.Enum): ADMIN = "admin" CR_RESPONSAVEL = "cr_responsavel" SETOR_RESPONSAVEL = "setor_responsavel" USUARIO = "usuario" class Usuario(Base, UserMixin): __tablename__ = 'usuarios' id = Column(Integer, primary_key=True) username = Column(String(50), unique=True, nullable=False) password_hash = Column(String(255), nullable=False) email = Column(String(100), unique=True, nullable=False) nome = Column(String(100)) # Nome completo do usuário otp_secret = Column(String(32)) role_id = Column(Integer, ForeignKey('roles.id')) setor_id = Column(Integer, ForeignKey('setores.id')) ativo = Column(Boolean, default=True) is_admin = Column(Boolean, default=False) ultimo_login = Column(DateTime) ultimo_logout = Column(DateTime) motivo_logout = Column(String(100)) cr_id = Column(Integer, ForeignKey('comites_regionais.id')) celula_id = Column(Integer, ForeignKey('celulas.id')) session_timeout = Column(Integer, default=30) tipo = Column(String(17), nullable=False) ultima_atividade = Column(DateTime, default=datetime.utcnow) # Relacionamento com militante militante_id = Column(Integer, ForeignKey('militantes.id')) # Relacionamentos roles = relationship("Role", secondary="user_roles", back_populates="users") setor = relationship('Setor', back_populates='usuarios') cr = relationship('ComiteRegional', back_populates='usuarios') celula = relationship('Celula', back_populates='usuarios') militante = relationship("Militante", backref=backref("usuario", uselist=False)) def __init__(self, username, email=None, is_admin=False, nome=None): self.username = username self.email = email self.is_admin = is_admin self.nome = nome self.ativo = True self.session_timeout = 30 self.tipo = "USUARIO" self.ultima_atividade = datetime.utcnow() def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) def update_last_activity(self): self.ultima_atividade = datetime.utcnow() def is_session_expired(self): if not self.ultima_atividade: return True time_diff = datetime.utcnow() - self.ultima_atividade return time_diff.total_seconds() > (self.session_timeout * 60) def check_session_timeout(self): """Verifica se a sessão do usuário expirou""" if not self.ultima_atividade: return True time_diff = datetime.utcnow() - self.ultima_atividade return time_diff.total_seconds() > (self.session_timeout * 60) def has_permission(self, permission_name): """Verifica se o usuário tem uma permissão específica""" if self.is_admin: # Se for admin, tem todas as permissões return True # Verifica se o usuário tem a permissão através de suas roles for role in self.roles: for permission in role.permissions: if permission.nome == permission_name: return True return False def has_role(self, role_nivel): """Verifica se o usuário tem um determinado nível de role""" for role in self.roles: if role.nivel == role_nivel: return True return False def get_otp_uri(self): """Gera a URI para autenticação em duas etapas""" if not self.otp_secret: self.otp_secret = pyotp.random_base32() return pyotp.totp.TOTP(self.otp_secret).provisioning_uri( self.username, issuer_name="Sistema de Controles" ) def verify_otp(self, code): """Verifica se um código OTP é válido""" if not self.otp_secret: print(f"Erro: OTP secret não configurado para o usuário {self.username}") return False totp = pyotp.totp.TOTP(self.otp_secret) is_valid = totp.verify(code) return is_valid def logout(self): """Registra o logout do usuário""" self.ultimo_logout = datetime.utcnow() self.motivo_logout = "Logout manual" self.ultima_atividade = None def is_admin_user(self): """Verifica se o usuário é admin""" return self.is_admin or any(role.nome == "admin" for role in self.roles)