from flask import Blueprint, request, render_template, redirect, url_for, flash, jsonify from functions.database import get_db_connection, Militante, EmailMilitante, Endereco, Celula, Setor, ComiteRegional from functions.decorators import require_login from functions.validations import validar_cpf from functions.rbac import Permission from utils.date_utils import validar_data, converter_data, calcular_idade from datetime import datetime from sqlalchemy.orm import joinedload from flask_login import current_user militante_bp = Blueprint('militante', __name__) @militante_bp.route("/militantes/criar", methods=["POST"]) @require_login def criar(): """Cria um novo militante""" try: data = request.get_json() # Validações básicas if not data.get('nome') or not data.get('cpf'): return jsonify({ 'status': 'error', 'message': 'Nome e CPF são obrigatórios' }), 400 if not validar_cpf(data['cpf']): return jsonify({ 'status': 'error', 'message': 'CPF inválido' }), 400 db = get_db_connection() # Verificar se CPF já existe if db.query(Militante).filter_by(cpf=data['cpf']).first(): return jsonify({ 'status': 'error', 'message': 'CPF já cadastrado' }), 400 # Criar endereço se fornecido endereco_id = None if data.get('endereco'): endereco = Endereco(**data['endereco']) db.add(endereco) db.flush() endereco_id = endereco.id # Criar militante militante = Militante( nome=data['nome'], cpf=data['cpf'], titulo_eleitoral=data.get('titulo_eleitoral'), data_nascimento=converter_data(data.get('data_nascimento')) if data.get('data_nascimento') else None, data_entrada_oci=converter_data(data.get('data_entrada_oci')) if data.get('data_entrada_oci') else None, data_efetivacao_oci=converter_data(data.get('data_efetivacao_oci')) if data.get('data_efetivacao_oci') else None, telefone1=data.get('telefone1'), telefone2=data.get('telefone2'), profissao=data.get('profissao'), regime_trabalho=data.get('regime_trabalho'), empresa=data.get('empresa'), contratante=data.get('contratante'), instituicao_ensino=data.get('instituicao_ensino'), tipo_instituicao=data.get('tipo_instituicao'), sindicato=data.get('sindicato'), cargo_sindical=data.get('cargo_sindical'), dirigente_sindical=data.get('dirigente_sindical', False), central_sindical=data.get('central_sindical'), endereco_id=endereco_id, celula_id=data.get('celula_id'), registrado_por=current_user.id ) db.add(militante) db.flush() # Criar email se fornecido if data.get('email'): email = EmailMilitante( militante_id=militante.id, endereco_email=data['email'] ) db.add(email) db.commit() return jsonify({ 'status': 'success', 'message': 'Militante criado com sucesso', 'militante_id': militante.id }) except Exception as e: db.rollback() return jsonify({ 'status': 'error', 'message': f'Erro ao criar militante: {str(e)}' }), 500 finally: db.close() @militante_bp.route("/militantes") @require_login def listar(): """Lista todos os militantes com controle de permissões no nível de dados""" db = get_db_connection() try: # SEMPRE renderizar o template, mas filtrar os dados baseado nas permissões militantes = [] # Verificar permissões para filtrar dados if current_user.is_admin: # Admin vê todos militantes = db.query(Militante).options( joinedload(Militante.emails), joinedload(Militante.endereco), joinedload(Militante.celula) ).order_by(Militante.nome).all() elif hasattr(current_user, 'has_permission'): if current_user.has_permission(Permission.VIEW_CC_REPORTS): # CC vê todos militantes = db.query(Militante).options( joinedload(Militante.emails), joinedload(Militante.endereco), joinedload(Militante.celula) ).order_by(Militante.nome).all() elif current_user.has_permission(Permission.VIEW_CR_REPORTS): # CR vê do seu CR if hasattr(current_user, 'cr_id') and current_user.cr_id: militantes = db.query(Militante).join(Celula).join(Setor).filter( Setor.cr_id == current_user.cr_id ).options( joinedload(Militante.emails), joinedload(Militante.endereco), joinedload(Militante.celula) ).order_by(Militante.nome).all() elif current_user.has_permission(Permission.VIEW_SECTOR_REPORTS): # Setor vê do seu setor if hasattr(current_user, 'setor_id') and current_user.setor_id: militantes = db.query(Militante).join(Celula).filter( Celula.setor_id == current_user.setor_id ).options( joinedload(Militante.emails), joinedload(Militante.endereco), joinedload(Militante.celula) ).order_by(Militante.nome).all() elif current_user.has_permission(Permission.VIEW_CELL_DATA): # Célula vê da sua célula if hasattr(current_user, 'celula_id') and current_user.celula_id: militantes = db.query(Militante).filter( Militante.celula_id == current_user.celula_id ).options( joinedload(Militante.emails), joinedload(Militante.endereco), joinedload(Militante.celula) ).order_by(Militante.nome).all() # Buscar dados auxiliares para o template celulas = db.query(Celula).all() setores = db.query(Setor).all() # SEMPRE renderizar o template, independente das permissões # O controle é feito no nível dos dados, não do template return render_template('listar_militantes.html', militantes=militantes, Militante=Militante, celulas=celulas, setores=setores) except Exception as e: print(f"Erro no controller de militantes: {e}") # Em caso de erro, renderizar com dados vazios return render_template('listar_militantes.html', militantes=[], Militante=Militante, celulas=[], setores=[]) finally: db.close() @militante_bp.route("/militantes/excluir/", methods=["POST"]) @require_login def excluir(id): """Exclui um militante""" db = get_db_connection() try: militante = db.query(Militante).get(id) if not militante: flash('Militante não encontrado.', 'danger') return redirect(url_for('militante.listar')) # Verificar permissões if not current_user.has_permission('gerenciar_militantes'): flash('Você não tem permissão para excluir militantes.', 'danger') return redirect(url_for('militante.listar')) db.delete(militante) db.commit() flash('Militante excluído com sucesso!', 'success') except Exception as e: db.rollback() flash('Erro ao excluir militante.', 'danger') print(f"Erro ao excluir militante: {e}") finally: db.close() return redirect(url_for('militante.listar')) @militante_bp.route('/militantes/editar/', methods=['POST']) @require_login def editar(militante_id): """Edita um militante existente""" try: data = request.get_json() db = get_db_connection() militante = db.query(Militante).get(militante_id) if not militante: return jsonify({ 'status': 'error', 'message': 'Militante não encontrado' }), 404 # Atualizar dados básicos militante.nome = data.get('nome', militante.nome) militante.cpf = data.get('cpf', militante.cpf) militante.titulo_eleitoral = data.get('titulo_eleitoral', militante.titulo_eleitoral) militante.telefone1 = data.get('telefone1', militante.telefone1) militante.telefone2 = data.get('telefone2', militante.telefone2) militante.profissao = data.get('profissao', militante.profissao) militante.regime_trabalho = data.get('regime_trabalho', militante.regime_trabalho) militante.empresa = data.get('empresa', militante.empresa) militante.contratante = data.get('contratante', militante.contratante) militante.instituicao_ensino = data.get('instituicao_ensino', militante.instituicao_ensino) militante.tipo_instituicao = data.get('tipo_instituicao', militante.tipo_instituicao) militante.sindicato = data.get('sindicato', militante.sindicato) militante.cargo_sindical = data.get('cargo_sindical', militante.cargo_sindical) militante.dirigente_sindical = data.get('dirigente_sindical', militante.dirigente_sindical) militante.central_sindical = data.get('central_sindical', militante.central_sindical) # Atualizar datas if data.get('data_nascimento'): militante.data_nascimento = converter_data(data['data_nascimento']) if data.get('data_entrada_oci'): militante.data_entrada_oci = converter_data(data['data_entrada_oci']) if data.get('data_efetivacao_oci'): militante.data_efetivacao_oci = converter_data(data['data_efetivacao_oci']) # Atualizar endereço if data.get('endereco') and militante.endereco: endereco = militante.endereco endereco.cep = data['endereco'].get('cep', endereco.cep) endereco.estado = data['endereco'].get('estado', endereco.estado) endereco.cidade = data['endereco'].get('cidade', endereco.cidade) endereco.bairro = data['endereco'].get('bairro', endereco.bairro) endereco.rua = data['endereco'].get('rua', endereco.rua) endereco.numero = data['endereco'].get('numero', endereco.numero) endereco.complemento = data['endereco'].get('complemento', endereco.complemento) # Atualizar email if data.get('email') and militante.emails: militante.emails[0].endereco_email = data['email'] db.commit() return jsonify({ 'status': 'success', 'message': 'Militante atualizado com sucesso' }) except Exception as e: db.rollback() return jsonify({ 'status': 'error', 'message': f'Erro ao atualizar militante: {str(e)}' }), 500 finally: db.close() @militante_bp.route("/militantes/dados/") @require_login def buscar_dados(militante_id): """Busca os dados de um militante específico""" db = get_db_connection() try: militante = db.query(Militante).options( joinedload(Militante.emails), joinedload(Militante.endereco) ).get(militante_id) if not militante: return jsonify({ 'status': 'error', 'message': 'Militante não encontrado' }), 404 # Função auxiliar para formatar data com validação def formatar_data_segura(data): try: if not data: return None return data.strftime('%Y-%m-%d') except Exception as e: print(f"Erro ao formatar data: {str(e)}, valor: {data}") return None # Preparar dados para retorno dados = { 'id': militante.id, 'nome': militante.nome, 'cpf': militante.cpf, 'titulo_eleitoral': militante.titulo_eleitoral, 'data_nascimento': formatar_data_segura(militante.data_nascimento), 'data_entrada_oci': formatar_data_segura(militante.data_entrada_oci), 'data_efetivacao_oci': formatar_data_segura(militante.data_efetivacao_oci), 'telefone1': militante.telefone1, 'telefone2': militante.telefone2, 'profissao': militante.profissao, 'regime_trabalho': militante.regime_trabalho, 'empresa': militante.empresa, 'contratante': militante.contratante, 'instituicao_ensino': militante.instituicao_ensino, 'tipo_instituicao': militante.tipo_instituicao, 'sindicato': militante.sindicato, 'cargo_sindical': militante.cargo_sindical, 'dirigente_sindical': militante.dirigente_sindical, 'central_sindical': militante.central_sindical, 'responsabilidades': militante.responsabilidades, 'estado': militante.estado.value if militante.estado else None, 'celula_id': militante.celula_id, 'email': militante.emails[0].endereco_email if militante.emails else None, 'endereco': { 'cep': militante.endereco.cep if militante.endereco else None, 'estado': militante.endereco.estado if militante.endereco else None, 'cidade': militante.endereco.cidade if militante.endereco else None, 'bairro': militante.endereco.bairro if militante.endereco else None, 'rua': militante.endereco.rua if militante.endereco else None, 'numero': militante.endereco.numero if militante.endereco else None, 'complemento': militante.endereco.complemento if militante.endereco else None } if militante.endereco else None } return jsonify({ 'status': 'success', 'data': dados }) except Exception as e: return jsonify({ 'status': 'error', 'message': f'Erro ao buscar dados: {str(e)}' }), 500 finally: db.close() @militante_bp.route("/api/setores/") @require_login def get_setores(cr_id): """Retorna setores de um CR específico""" db = get_db_connection() try: setores = db.query(Setor).filter_by(cr_id=cr_id).all() return jsonify([{'id': s.id, 'nome': s.nome} for s in setores]) finally: db.close()