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:
164
app.py
164
app.py
@@ -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"])
|
||||||
|
|||||||
@@ -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 = '';
|
||||||
}
|
}
|
||||||
@@ -667,10 +667,41 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
formEditarMilitante.addEventListener('submit', async function(event) {
|
formEditarMilitante.addEventListener('submit', async function(event) {
|
||||||
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);
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user