refactor: melhorias na interface e funcionalidades - Atualização do layout do dashboard com Bootstrap 5 - Remoção do template editar_pagamento.html (integrado ao modal) - Melhorias no template home.html com cards estatísticos - Ajustes nos estilos e responsividade - Correções nas rotas e conexões do banco de dados - Implementação do modal de edição de pagamentos - Adição de efeitos hover e melhorias visuais
This commit is contained in:
107
app.py
107
app.py
@@ -243,6 +243,7 @@ def home():
|
|||||||
total_materiais = db.query(func.sum(MaterialVendido.valor)).scalar() or 0
|
total_materiais = db.query(func.sum(MaterialVendido.valor)).scalar() or 0
|
||||||
total_assinaturas = db.query(func.sum(AssinaturaAnual.valor)).scalar() or 0
|
total_assinaturas = db.query(func.sum(AssinaturaAnual.valor)).scalar() or 0
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
return render_template(
|
return render_template(
|
||||||
"home.html",
|
"home.html",
|
||||||
nome_usuario=nome_usuario,
|
nome_usuario=nome_usuario,
|
||||||
@@ -252,6 +253,48 @@ def home():
|
|||||||
total_materiais=total_materiais,
|
total_materiais=total_materiais,
|
||||||
total_assinaturas=total_assinaturas
|
total_assinaturas=total_assinaturas
|
||||||
)
|
)
|
||||||
|
=======
|
||||||
|
# Buscar últimos militantes cadastrados
|
||||||
|
ultimos_militantes = db.query(Militante)\
|
||||||
|
.order_by(Militante.id.desc())\
|
||||||
|
.limit(5)\
|
||||||
|
.all()
|
||||||
|
|
||||||
|
# Buscar últimos pagamentos
|
||||||
|
ultimos_pagamentos = db.query(Pagamento)\
|
||||||
|
.join(Militante)\
|
||||||
|
.order_by(Pagamento.data_pagamento.desc())\
|
||||||
|
.limit(5)\
|
||||||
|
.all()
|
||||||
|
|
||||||
|
# Buscar tipos de pagamento
|
||||||
|
tipos_pagamento = db.query(TipoPagamento).all()
|
||||||
|
|
||||||
|
return render_template('home.html',
|
||||||
|
nome_usuario=nome_usuario,
|
||||||
|
data_atual=data_formatada,
|
||||||
|
total_militantes=total_militantes,
|
||||||
|
total_cotas="{:.2f}".format(total_cotas),
|
||||||
|
total_materiais=total_materiais,
|
||||||
|
total_assinaturas=total_assinaturas,
|
||||||
|
ultimos_militantes=ultimos_militantes,
|
||||||
|
ultimos_pagamentos=ultimos_pagamentos,
|
||||||
|
tipos_pagamento=tipos_pagamento)
|
||||||
|
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', 'danger')
|
||||||
|
return render_template('home.html',
|
||||||
|
nome_usuario="Usuário",
|
||||||
|
data_atual=datetime.now().strftime("%d/%m/%Y"),
|
||||||
|
total_militantes=0,
|
||||||
|
total_cotas="0.00",
|
||||||
|
total_materiais=0,
|
||||||
|
total_assinaturas=0,
|
||||||
|
ultimos_militantes=[],
|
||||||
|
ultimos_pagamentos=[])
|
||||||
|
>>>>>>> 324660d (refactor: melhorias na interface e funcionalidades - Atualização do layout do dashboard com Bootstrap 5 - Remoção do template editar_pagamento.html (integrado ao modal) - Melhorias no template home.html com cards estatísticos - Ajustes nos estilos e responsividade - Correções nas rotas e conexões do banco de dados - Implementação do modal de edição de pagamentos - Adição de efeitos hover e melhorias visuais)
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
@@ -1275,6 +1318,7 @@ def toggle_quadro_orientador(user_id):
|
|||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
@app.route('/usuarios/<int:user_id>/toggle_aspirante', methods=['POST'])
|
@app.route('/usuarios/<int:user_id>/toggle_aspirante', methods=['POST'])
|
||||||
@require_login
|
@require_login
|
||||||
def toggle_aspirante(user_id):
|
def toggle_aspirante(user_id):
|
||||||
@@ -1477,6 +1521,69 @@ def session_timeout():
|
|||||||
db_session.commit()
|
db_session.commit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erro ao atualizar última atividade: {e}")
|
print(f"Erro ao atualizar última atividade: {e}")
|
||||||
|
=======
|
||||||
|
# API Routes para os modais
|
||||||
|
@app.route('/api/pagamentos/<int:id>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def get_pagamento(id):
|
||||||
|
db = get_db_connection()
|
||||||
|
try:
|
||||||
|
pagamento = db.query(Pagamento).get(id)
|
||||||
|
if not pagamento:
|
||||||
|
return jsonify({'success': False, 'message': 'Pagamento não encontrado'}), 404
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'id': pagamento.id,
|
||||||
|
'valor': pagamento.valor,
|
||||||
|
'data_pagamento': pagamento.data_pagamento.strftime('%Y-%m-%d'),
|
||||||
|
'tipo_pagamento_id': pagamento.tipo_pagamento_id,
|
||||||
|
'observacao': pagamento.observacao
|
||||||
|
})
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
@app.route('/api/pagamentos/<int:id>', methods=['PUT'])
|
||||||
|
@login_required
|
||||||
|
def update_pagamento(id):
|
||||||
|
db = get_db_connection()
|
||||||
|
try:
|
||||||
|
pagamento = db.query(Pagamento).get(id)
|
||||||
|
if not pagamento:
|
||||||
|
return jsonify({'success': False, 'message': 'Pagamento não encontrado'}), 404
|
||||||
|
|
||||||
|
try:
|
||||||
|
pagamento.valor = float(request.form['valor'])
|
||||||
|
pagamento.data_pagamento = datetime.strptime(request.form['data_pagamento'], '%Y-%m-%d')
|
||||||
|
pagamento.tipo_pagamento_id = int(request.form['tipo_pagamento'])
|
||||||
|
pagamento.observacao = request.form['observacao']
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
return jsonify({'success': True})
|
||||||
|
except Exception as e:
|
||||||
|
db.rollback()
|
||||||
|
return jsonify({'success': False, 'message': str(e)}), 400
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
@app.route('/api/pagamentos/<int:id>', methods=['DELETE'])
|
||||||
|
@login_required
|
||||||
|
def delete_pagamento(id):
|
||||||
|
db = get_db_connection()
|
||||||
|
try:
|
||||||
|
pagamento = db.query(Pagamento).get(id)
|
||||||
|
if not pagamento:
|
||||||
|
return jsonify({'success': False, 'message': 'Pagamento não encontrado'}), 404
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.delete(pagamento)
|
||||||
|
db.commit()
|
||||||
|
return jsonify({'success': True})
|
||||||
|
except Exception as e:
|
||||||
|
db.rollback()
|
||||||
|
return jsonify({'success': False, 'message': str(e)}), 400
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
>>>>>>> 324660d (refactor: melhorias na interface e funcionalidades - Atualização do layout do dashboard com Bootstrap 5 - Remoção do template editar_pagamento.html (integrado ao modal) - Melhorias no template home.html com cards estatísticos - Ajustes nos estilos e responsividade - Correções nas rotas e conexões do banco de dados - Implementação do modal de edição de pagamentos - Adição de efeitos hover e melhorias visuais)
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Editar Pagamento{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-4">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h5 class="card-title mb-0">
|
|
||||||
<i class="fas fa-edit me-2"></i>Editar Pagamento
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<form method="post">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="valor" class="form-label">Valor</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text">R$</span>
|
|
||||||
<input type="number" step="0.01" class="form-control" id="valor" name="valor" value="{{ pagamento.valor }}" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="data_pagamento" class="form-label">Data do Pagamento</label>
|
|
||||||
<input type="date" class="form-control" id="data_pagamento" name="data_pagamento" value="{{ pagamento.data_pagamento.strftime('%Y-%m-%d') }}" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="tipo_pagamento" class="form-label">Tipo de Pagamento</label>
|
|
||||||
<select class="form-select" id="tipo_pagamento" name="tipo_pagamento" required>
|
|
||||||
{% for tipo in tipos_pagamento %}
|
|
||||||
<option value="{{ tipo.id }}" {% if tipo.id == pagamento.tipo_pagamento_id %}selected{% endif %}>
|
|
||||||
{{ tipo.nome }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="observacao" class="form-label">Observação</label>
|
|
||||||
<textarea class="form-control" id="observacao" name="observacao" rows="3">{{ pagamento.observacao }}</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-end gap-2">
|
|
||||||
<a href="{{ url_for('listar_pagamentos') }}" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-times me-2"></i>Cancelar
|
|
||||||
</a>
|
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<i class="fas fa-save me-2"></i>Salvar Alterações
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -108,12 +108,31 @@
|
|||||||
{% if ultimos_pagamentos %}
|
{% if ultimos_pagamentos %}
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
{% for pagamento in ultimos_pagamentos %}
|
{% for pagamento in ultimos_pagamentos %}
|
||||||
<div class="list-group-item" onclick="window.location='{{ url_for('editar_pagamento', id=pagamento.id) }}'">
|
<div class="list-group-item" style="cursor: pointer" onclick="carregarDadosPagamento({{ pagamento.id }})">
|
||||||
<div class="militante-info">
|
<div class="militante-info">
|
||||||
<h6 class="mb-1">{{ pagamento.militante.nome }}</h6>
|
<h6 class="mb-1">{{ pagamento.militante.nome }}</h6>
|
||||||
<small>{{ pagamento.data_pagamento.strftime('%d/%m/%Y') }}</small>
|
<small>{{ pagamento.data_pagamento.strftime('%d/%m/%Y') }}</small>
|
||||||
</div>
|
</div>
|
||||||
<span class="badge bg-success">R$ {{ "%.2f"|format(pagamento.valor) }}</span>
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<span class="badge bg-success">R$ {{ "%.2f"|format(pagamento.valor) }}</span>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-link text-secondary p-0" type="button" data-bs-toggle="dropdown">
|
||||||
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="#" onclick="event.stopPropagation(); carregarDadosPagamento({{ pagamento.id }})">
|
||||||
|
<i class="fas fa-edit me-2"></i>Editar
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item text-danger" href="#" onclick="event.stopPropagation(); confirmarExclusao({{ pagamento.id }}, 'pagamentos')">
|
||||||
|
<i class="fas fa-trash me-2"></i>Excluir
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@@ -226,21 +245,84 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal de Exclusão -->
|
<!-- Modal de Edição de Pagamento -->
|
||||||
|
<div class="modal fade" id="modalEditarPagamento" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
<i class="fas fa-money-bill-wave me-2"></i>Editar Pagamento
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="formEditarPagamento" method="post">
|
||||||
|
<input type="hidden" id="editPagamentoId" name="id">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="editValor" class="form-label">Valor</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text">R$</span>
|
||||||
|
<input type="number" step="0.01" class="form-control" id="editValor" name="valor" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="editDataPagamento" class="form-label">Data do Pagamento</label>
|
||||||
|
<input type="date" class="form-control" id="editDataPagamento" name="data_pagamento" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="editTipoPagamento" class="form-label">Tipo de Pagamento</label>
|
||||||
|
<select class="form-select" id="editTipoPagamento" name="tipo_pagamento" required>
|
||||||
|
{% for tipo in tipos_pagamento %}
|
||||||
|
<option value="{{ tipo.id }}">{{ tipo.nome }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="editObservacao" class="form-label">Observação</label>
|
||||||
|
<textarea class="form-control" id="editObservacao" name="observacao" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
|
<i class="fas fa-times me-2"></i>Cancelar
|
||||||
|
</button>
|
||||||
|
<button type="submit" form="formEditarPagamento" class="btn btn-primary">
|
||||||
|
<i class="fas fa-save me-2"></i>Salvar Alterações
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal de Confirmação de Exclusão -->
|
||||||
<div class="modal fade" id="deleteModal" tabindex="-1">
|
<div class="modal fade" id="deleteModal" tabindex="-1">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">Confirmar Exclusão</h5>
|
<h5 class="modal-title">
|
||||||
|
<i class="fas fa-exclamation-triangle me-2"></i>Confirmar Exclusão
|
||||||
|
</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<<<<<<< HEAD
|
||||||
<p>Tem certeza que deseja excluir este militante?</p>
|
<p>Tem certeza que deseja excluir este militante?</p>
|
||||||
<p class="text-danger">Esta ação não pode ser desfeita.</p>
|
<p class="text-danger">Esta ação não pode ser desfeita.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
||||||
<button type="button" class="btn btn-danger" id="confirmDelete">
|
<button type="button" class="btn btn-danger" id="confirmDelete">
|
||||||
|
=======
|
||||||
|
<p>Tem certeza que deseja excluir este item?</p>
|
||||||
|
<p class="text-danger"><small>Esta ação não pode ser desfeita.</small></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
|
<i class="fas fa-times me-2"></i>Cancelar
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="btnConfirmarExclusao">
|
||||||
|
>>>>>>> 324660d (refactor: melhorias na interface e funcionalidades - Atualização do layout do dashboard com Bootstrap 5 - Remoção do template editar_pagamento.html (integrado ao modal) - Melhorias no template home.html com cards estatísticos - Ajustes nos estilos e responsividade - Correções nas rotas e conexões do banco de dados - Implementação do modal de edição de pagamentos - Adição de efeitos hover e melhorias visuais)
|
||||||
<i class="fas fa-trash me-2"></i>Excluir
|
<i class="fas fa-trash me-2"></i>Excluir
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -350,5 +432,87 @@
|
|||||||
deleteMilitante(id);
|
deleteMilitante(id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
|
// Função para carregar dados do pagamento no modal
|
||||||
|
function carregarDadosPagamento(id) {
|
||||||
|
fetch(`/api/pagamentos/${id}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
document.getElementById('editPagamentoId').value = data.id;
|
||||||
|
document.getElementById('editValor').value = data.valor;
|
||||||
|
document.getElementById('editDataPagamento').value = data.data_pagamento;
|
||||||
|
document.getElementById('editTipoPagamento').value = data.tipo_pagamento_id;
|
||||||
|
document.getElementById('editObservacao').value = data.observacao || '';
|
||||||
|
|
||||||
|
// Abre o modal
|
||||||
|
new bootstrap.Modal(document.getElementById('modalEditarPagamento')).show();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Erro ao carregar dados:', error);
|
||||||
|
alert('Erro ao carregar dados do pagamento');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Função para salvar alterações do pagamento
|
||||||
|
document.getElementById('formEditarPagamento').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const id = document.getElementById('editPagamentoId').value;
|
||||||
|
const formData = new FormData(this);
|
||||||
|
|
||||||
|
fetch(`/api/pagamentos/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
// Fecha o modal
|
||||||
|
bootstrap.Modal.getInstance(document.getElementById('modalEditarPagamento')).hide();
|
||||||
|
// Recarrega a página
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Erro ao salvar alterações: ' + data.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Erro ao salvar:', error);
|
||||||
|
alert('Erro ao salvar alterações');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configuração do modal de exclusão
|
||||||
|
let itemParaExcluir = null;
|
||||||
|
let tipoItem = null;
|
||||||
|
|
||||||
|
function confirmarExclusao(id, tipo) {
|
||||||
|
itemParaExcluir = id;
|
||||||
|
tipoItem = tipo;
|
||||||
|
new bootstrap.Modal(document.getElementById('deleteModal')).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('btnConfirmarExclusao').addEventListener('click', function() {
|
||||||
|
if (!itemParaExcluir || !tipoItem) return;
|
||||||
|
|
||||||
|
fetch(`/api/${tipoItem}/${itemParaExcluir}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Erro ao excluir: ' + data.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Erro ao excluir:', error);
|
||||||
|
alert('Erro ao excluir item');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
>>>>>>> 324660d (refactor: melhorias na interface e funcionalidades - Atualização do layout do dashboard com Bootstrap 5 - Remoção do template editar_pagamento.html (integrado ao modal) - Melhorias no template home.html com cards estatísticos - Ajustes nos estilos e responsividade - Correções nas rotas e conexões do banco de dados - Implementação do modal de edição de pagamentos - Adição de efeitos hover e melhorias visuais)
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user