fix: corrige validação e salvamento do formulário de edição de militante - Corrige validação do email, ajusta conversão de datas, corrige CSRF token e melhora feedback visual

This commit is contained in:
andersonid
2025-04-07 03:42:01 -03:00
committed by LS
parent 179ea3cad0
commit 3f2e6e3022
3 changed files with 116 additions and 115 deletions

164
app.py
View File

@@ -940,146 +940,112 @@ def create_app():
db.close() db.close()
# Rota para editar militante # Rota para editar militante
@app.route("/militantes/editar/<int:militante_id>", methods=["POST"]) @app.route('/militantes/editar/<int:militante_id>', methods=['POST'])
@require_login @login_required
@require_permission('gerenciar_militantes') @require_permission('gerenciar_militantes')
def editar_militante(militante_id): def editar_militante(militante_id):
"""Edita um militante existente"""
# Verificar token CSRF manualmente
csrf_token = request.headers.get('X-CSRFToken') or request.form.get('csrf_token')
if not csrf_token or not csrf.validate_csrf(csrf_token):
return jsonify({
'status': 'error',
'message': 'Token CSRF inválido'
}), 400
db = get_db_connection()
try: try:
militante = db.query(Militante).get(militante_id) # Verificar se o militante existe
militante = db_session.query(Militante).get(militante_id)
if not militante: if not militante:
return jsonify({ return jsonify({
'status': 'error', 'status': 'error',
'message': 'Militante não encontrado' 'message': 'Militante não encontrado'
}), 404 }), 404
# Dados Básicos # Obter dados do formulário
militante.nome = request.form.get('nome') nome = request.form.get('nome')
militante.cpf = request.form.get('cpf') cpf = request.form.get('cpf')
militante.titulo_eleitoral = request.form.get('titulo_eleitoral') titulo_eleitoral = request.form.get('titulo_eleitoral')
militante.data_nascimento = datetime.strptime(request.form.get('data_nascimento'), '%Y-%m-%d') if request.form.get('data_nascimento') else None data_nascimento = request.form.get('data_nascimento')
militante.data_entrada_oci = datetime.strptime(request.form.get('data_entrada_oci'), '%Y-%m-%d') if request.form.get('data_entrada_oci') else None data_entrada_oci = request.form.get('data_entrada_oci')
militante.data_efetivacao_oci = datetime.strptime(request.form.get('data_efetivacao_oci'), '%Y-%m-%d') if request.form.get('data_efetivacao_oci') else None data_efetivacao_oci = request.form.get('data_efetivacao_oci')
telefone1 = request.form.get('telefone1')
# Contato telefone2 = request.form.get('telefone2')
militante.telefone1 = request.form.get('telefone1')
militante.telefone2 = request.form.get('telefone2')
# Email (atualizar o principal)
email = request.form.get('email') email = request.form.get('email')
# Converter datas para objetos date
data_nascimento = datetime.strptime(data_nascimento, '%Y-%m-%d').date() if data_nascimento else None
data_entrada_oci = datetime.strptime(data_entrada_oci, '%Y-%m-%d').date() if data_entrada_oci else None
data_efetivacao_oci = datetime.strptime(data_efetivacao_oci, '%Y-%m-%d').date() if data_efetivacao_oci else None
# Atualizar dados básicos
militante.nome = nome
militante.cpf = cpf
militante.titulo_eleitoral = titulo_eleitoral
militante.data_nascimento = data_nascimento
militante.data_entrada_oci = data_entrada_oci
militante.data_efetivacao_oci = data_efetivacao_oci
militante.telefone1 = telefone1
militante.telefone2 = telefone2
# Atualizar email
if email: if email:
if militante.emails: # Verificar se já existe um email para este militante
militante.emails[0].endereco_email = email email_existente = db_session.query(EmailMilitante).filter_by(militante_id=militante_id).first()
if email_existente:
email_existente.endereco_email = email
else: else:
novo_email = EmailMilitante( novo_email = EmailMilitante(endereco_email=email, militante_id=militante_id)
endereco_email=email, db_session.add(novo_email)
militante_id=militante.id
) # Atualizar endereço
db.add(novo_email) endereco = militante.endereco or Endereco(militante_id=militante_id)
militante.emails.append(novo_email) endereco.cep = request.form.get('cep')
endereco.estado = request.form.get('estado')
endereco.cidade = request.form.get('cidade')
endereco.bairro = request.form.get('bairro')
endereco.rua = request.form.get('rua')
endereco.numero = request.form.get('numero')
endereco.complemento = request.form.get('complemento')
# Endereço
if not militante.endereco: if not militante.endereco:
militante.endereco = Endereco() militante.endereco = endereco
db.add(militante.endereco) db_session.add(endereco)
militante.endereco.cep = request.form.get('cep') # Atualizar dados profissionais
militante.endereco.estado = request.form.get('estado')
militante.endereco.cidade = request.form.get('cidade')
militante.endereco.bairro = request.form.get('bairro')
militante.endereco.rua = request.form.get('rua')
militante.endereco.numero = request.form.get('numero')
militante.endereco.complemento = request.form.get('complemento')
# Profissional
militante.profissao = request.form.get('profissao')
militante.regime_trabalho = request.form.get('regime_trabalho')
militante.empresa = request.form.get('empresa') militante.empresa = request.form.get('empresa')
militante.contratante = request.form.get('contratante') militante.contratante = request.form.get('contratante')
# Acadêmico
militante.instituicao_ensino = request.form.get('instituicao_ensino') militante.instituicao_ensino = request.form.get('instituicao_ensino')
militante.tipo_instituicao = request.form.get('tipo_instituicao') militante.tipo_instituicao = request.form.get('tipo_instituicao')
# Sindical # Atualizar dados sindicais
militante.sindicato = request.form.get('sindicato') militante.sindicato = request.form.get('sindicato')
militante.cargo_sindical = request.form.get('cargo_sindical') militante.cargo_sindical = request.form.get('cargo_sindical')
militante.central_sindical = request.form.get('central_sindical') militante.central_sindical = request.form.get('central_sindical')
militante.dirigente_sindical = request.form.get('dirigente_sindical') == 'on' militante.dirigente_sindical = request.form.get('dirigente_sindical') == 'true'
# Organização # Atualizar responsabilidades
estado_str = request.form.get('estado', 'ATIVO').lower()
print(f"Estado recebido: {estado_str}")
# Converter o estado para o enum
try:
militante.estado = EstadoMilitante[estado_str.upper()]
print(f"Estado convertido: {militante.estado}")
except (KeyError, ValueError) as e:
print(f"Erro ao converter estado: {str(e)}")
return jsonify({
'status': 'error',
'message': f'Estado inválido: {estado_str}'
}), 400
# Tratar celula_id corretamente
celula_id = request.form.get('celula_id')
if celula_id:
try:
militante.celula_id = int(celula_id)
except (ValueError, TypeError):
militante.celula_id = None
else:
militante.celula_id = None
# Tratar responsabilidades corretamente
try: try:
responsabilidades_valor = request.form.get('responsabilidades_valor') responsabilidades_valor = request.form.get('responsabilidades_valor')
if responsabilidades_valor: if responsabilidades_valor:
militante.responsabilidades = int(responsabilidades_valor) militante.responsabilidades = int(responsabilidades_valor)
print(f"Responsabilidades atualizadas: {militante.responsabilidades}") print(f"Responsabilidades atualizadas para: {militante.responsabilidades}")
else: else:
militante.responsabilidades = 0 militante.responsabilidades = 0
print("Responsabilidades zeradas") print("Nenhuma responsabilidade definida")
except (ValueError, TypeError) as e: except (ValueError, TypeError) as e:
print(f"Erro ao processar responsabilidades: {str(e)}") print(f"Erro ao processar responsabilidades: {e}")
militante.responsabilidades = 0 militante.responsabilidades = 0
# Se o estado mudou para DESLIGADO, registrar data e motivo # Salvar alterações
if militante.estado == EstadoMilitante.DESLIGADO: db_session.commit()
militante.data_desligamento = datetime.now() print("Alterações salvas com sucesso!")
militante.motivo_desligamento = request.form.get('motivo_desligamento')
db.commit()
print("Alterações salvas com sucesso")
# Retornar as responsabilidades atualizadas
responsabilidades = militante.get_responsabilidades()
# Retornar resposta
return jsonify({ return jsonify({
'status': 'success', 'status': 'success',
'message': f'Militante {militante.nome} atualizado com sucesso!', 'message': 'Militante atualizado com sucesso!',
'responsabilidades': responsabilidades, 'responsabilidades': militante.get_responsabilidades()
'responsabilidades_valor': militante.responsabilidades
}) })
except Exception as e: except Exception as e:
print(f"Erro ao atualizar militante: {str(e)}") db_session.rollback()
db.rollback() print(f"Erro ao salvar alterações: {e}")
return jsonify({ return jsonify({
'status': 'error', 'status': 'error',
'message': f'Erro ao atualizar militante: {str(e)}' 'message': str(e)
}), 500 }), 500
finally:
db.close()
# Rota para criar um novo usuário # Rota para criar um novo usuário
@app.route("/usuarios/novo", methods=["GET", "POST"]) @app.route("/usuarios/novo", methods=["GET", "POST"])

View File

@@ -317,7 +317,7 @@ async function carregarDadosMilitante(militanteId) {
const emailElement = document.getElementById('edit_email'); const emailElement = document.getElementById('edit_email');
if (emailElement) { if (emailElement) {
if (data.emails && data.emails.length > 0) { if (data.emails && data.emails.length > 0) {
emailElement.value = data.emails[0].endereco_email; emailElement.value = data.emails[0]; // O email já vem como string
} else { } else {
emailElement.value = ''; emailElement.value = '';
} }
@@ -568,7 +568,7 @@ document.addEventListener('DOMContentLoaded', function() {
const emailElement = document.getElementById('edit_email'); const emailElement = document.getElementById('edit_email');
if (emailElement) { if (emailElement) {
if (data.emails && data.emails.length > 0) { if (data.emails && data.emails.length > 0) {
emailElement.value = data.emails[0].endereco_email; emailElement.value = data.emails[0]; // O email já vem como string
} else { } else {
emailElement.value = ''; emailElement.value = '';
} }
@@ -668,9 +668,40 @@ document.addEventListener('DOMContentLoaded', function() {
event.preventDefault(); event.preventDefault();
console.log('Formulário de edição enviado'); console.log('Formulário de edição enviado');
// Validar todos os campos antes do envio
const form = this;
form.classList.add('was-validated');
// Verificar se o formulário é válido
if (!form.checkValidity()) {
event.stopPropagation();
// Encontrar o primeiro campo inválido
const invalidField = form.querySelector(':invalid');
if (invalidField) {
// Encontrar a aba que contém o campo inválido
const tabPane = invalidField.closest('.tab-pane');
if (tabPane) {
// Ativar a aba
const tabId = tabPane.id;
const tab = document.querySelector(`button[data-bs-target="#${tabId}"]`);
if (tab) {
const bsTab = new bootstrap.Tab(tab);
bsTab.show();
// Focar no campo inválido após a aba ser exibida
setTimeout(() => {
invalidField.focus();
}, 200);
}
}
}
return;
}
// Se chegou aqui, o formulário é válido
// Obter ID do militante // Obter ID do militante
const militanteId = document.getElementById('edit_militante_id').value; const militanteId = document.getElementById('edit_militante_id').value;
console.log('ID do militante:', militanteId);
if (!militanteId) { if (!militanteId) {
console.error('ID do militante não encontrado'); console.error('ID do militante não encontrado');
@@ -679,24 +710,21 @@ document.addEventListener('DOMContentLoaded', function() {
} }
// Criar FormData com todos os campos // Criar FormData com todos os campos
const formData = new FormData(this); const formData = new FormData(form);
// Garantir que o valor das responsabilidades seja enviado // Garantir que o valor das responsabilidades seja enviado
const responsabilidadesValue = document.getElementById('responsabilidades_values').value; const responsabilidadesValue = document.getElementById('responsabilidades_values').value;
formData.set('responsabilidades_valor', responsabilidadesValue); formData.set('responsabilidades_valor', responsabilidadesValue);
console.log('Valor das responsabilidades sendo enviado:', responsabilidadesValue);
try { try {
// Construir URL
const url = `/militantes/editar/${militanteId}`; const url = `/militantes/editar/${militanteId}`;
console.log('URL da requisição:', url); const csrfToken = document.querySelector('input[name="csrf_token"]').value;
// Enviar requisição
const response = await fetch(url, { const response = await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest', 'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': getCsrfToken() 'X-CSRF-Token': csrfToken
}, },
body: formData body: formData
}); });
@@ -706,17 +734,11 @@ document.addEventListener('DOMContentLoaded', function() {
} }
const data = await response.json(); const data = await response.json();
console.log('Resposta do servidor:', data);
if (data.status === 'success') { if (data.status === 'success') {
// Fechar modal
const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante')); const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante'));
modal.hide(); modal.hide();
// Mostrar mensagem de sucesso
mostrarAlerta('Militante atualizado com sucesso!', 'success'); mostrarAlerta('Militante atualizado com sucesso!', 'success');
// Recarregar página após um pequeno delay para a mensagem ser vista
setTimeout(() => { setTimeout(() => {
location.reload(); location.reload();
}, 1000); }, 1000);

View File

@@ -44,10 +44,16 @@
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label for="edit_nome" class="form-label">Nome</label> <label for="edit_nome" class="form-label">Nome</label>
<input type="text" class="form-control" id="edit_nome" name="nome" required> <input type="text" class="form-control" id="edit_nome" name="nome" required>
<div class="invalid-feedback">
Por favor, insira o nome do militante.
</div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label for="edit_cpf" class="form-label">CPF</label> <label for="edit_cpf" class="form-label">CPF</label>
<input type="text" class="form-control" id="edit_cpf" name="cpf" required> <input type="text" class="form-control" id="edit_cpf" name="cpf" required>
<div class="invalid-feedback">
Por favor, insira um CPF válido.
</div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@@ -91,7 +97,14 @@
<!-- Email Principal --> <!-- Email Principal -->
<div class="mb-3"> <div class="mb-3">
<label for="edit_email" class="form-label">Email Principal</label> <label for="edit_email" class="form-label">Email Principal</label>
<input type="email" class="form-control" id="edit_email" name="email" required> <input type="email"
class="form-control"
id="edit_email"
name="email"
required>
<div class="invalid-feedback">
Por favor, insira um email válido.
</div>
</div> </div>
<!-- Endereço --> <!-- Endereço -->