Ajax pour la supression de vote et modifications de patrons
This commit is contained in:
parent
6a797d3357
commit
bca8d03400
12 changed files with 227 additions and 89 deletions
|
@ -4,38 +4,16 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
<div class="level mb-2">
|
||||
<div class="level mb-2 is-mobile">
|
||||
{# Titre de l'élection #}
|
||||
<div class="level-left is-flex-shrink-1">
|
||||
<div class="level-left is-flex-shrink-1 pr-3">
|
||||
<h1 class="title">{{ election.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="level-right is-flex">
|
||||
{# Liste des votant·e·s #}
|
||||
<div class="level-item is-flex-grow-1 mb-0">
|
||||
<a class="button is-primary is-light is-outlined" href="{% url 'election.voters' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
</span>
|
||||
<span>{% trans "Votant·e·s" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Liste des bulletins #}
|
||||
{% if election.results_public %}
|
||||
<div class="level-item is-flex-grow-1 mb-0">
|
||||
<a class="button is-primary is-light is-outlined" href="{% url 'election.ballots' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-list"></i>
|
||||
</span>
|
||||
<span>{% trans "Bulletins" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if election.start_date < current_time %}
|
||||
<div class="level-right is-flex is-flex-shrink-1">
|
||||
{# Statut de l'élection #}
|
||||
<div class="level-item is-flex-grow-1 mb-0">
|
||||
{% if election.start_date < current_time %}
|
||||
<div class="level-item is-flex-shrink-1">
|
||||
<span class="tag is-medium is-outlined is-light is-primary">
|
||||
{% if election.end_date < current_time %}
|
||||
{% trans "Élection terminée" %}
|
||||
|
@ -46,51 +24,84 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="level-item">
|
||||
<div class="dropdown is-right">
|
||||
<div class="dropdown-trigger">
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
|
||||
<span class="icon">
|
||||
<i class="fas fa-ellipsis-v" aria-hidden="true"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-menu" id="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
{# Lien vers la page d'administration #}
|
||||
{% if election.created_by == user %}
|
||||
<div class="level-item is-flex-grow-1">
|
||||
<a class="button has-tooltip-primary" href="{% url 'election.admin' election.pk %}" data-tooltip="{% trans "Administrer" %}">
|
||||
<a class="dropdown-item" href="{% url 'election.admin' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-cog"></i>
|
||||
</span>
|
||||
<span>{% trans "Administrer" %}</span>
|
||||
</a>
|
||||
|
||||
<hr class="dropdown-divider">
|
||||
{% endif %}
|
||||
|
||||
{# Liste des votant·e·s #}
|
||||
<a class="dropdown-item" href="{% url 'election.voters' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
</span>
|
||||
<span>{% trans "Votant·e·s" %}</span>
|
||||
</a>
|
||||
|
||||
{# Liste des bulletins #}
|
||||
{% if election.results_public %}
|
||||
<a class="dropdown-item" href="{% url 'election.ballots' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-list"></i>
|
||||
</span>
|
||||
<span>{% trans "Bulletins" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level mb-2">
|
||||
<div class="level">
|
||||
{# Dates d'ouverture de l'élection #}
|
||||
<div class="level-left is-flex">
|
||||
<div class="level-item is-flex-grow-1 mb-0">
|
||||
<div class="level-left is-flex-shrink-1 pr-3">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-item">
|
||||
<span class="tag is-medium is-primary">
|
||||
<span class="icon-text">
|
||||
<span>{{ election.start_date|date:"d/m/Y H:i" }}</span>
|
||||
<span class="icon">
|
||||
<i class="fas fa-long-arrow-alt-right"></i>
|
||||
</span>
|
||||
<span>{{ election.end_date|date:"d/m/Y H:i" }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{# Créateurice de l'élection #}
|
||||
<div class="level-item is-flex-grow-1 mb-0">
|
||||
<div class="level-item is-flex-shrink-1">
|
||||
<span class="tag is-primary is-light is-outlined">{% blocktrans with creator=election.created_by.full_name %}Créé par {{ creator }}{% endblocktrans %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Confirmation de vote #}
|
||||
{% if has_voted %}
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<div class="level-right is-flex-shrink-1">
|
||||
<div class="level-item is-flex-shrink-1">
|
||||
<div class="tag is-medium is-outlined is-success is-light">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>{% trans "Votre vote a bien été enregistré." %}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
b.addEventListener('click', () => {
|
||||
const f = _$('form', _id(b.dataset.target), false);
|
||||
f.dataset.next = b.dataset.next;
|
||||
f.dataset.modal = b.dataset.target;
|
||||
f.dataset.origin = b.dataset.parent
|
||||
|
||||
if (b.dataset.type == 'question') {
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
|
||||
{% block content %}
|
||||
<div class="level">
|
||||
<div class="level is-mobile">
|
||||
{# Titre de l'élection #}
|
||||
<div class="level-left is-flex-shrink-1">
|
||||
<div class="level-left is-flex-shrink-1 pr-3">
|
||||
<h1 class="title">{{ election.name }}</h1>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -26,42 +26,38 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
<div class="level is-flex-widescreen">
|
||||
<div class="level-left">
|
||||
<div class="item-level">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left is-flex-shrink-1">
|
||||
<div class="item-level is-flex-shrink-1 pr-3">
|
||||
<h1 class="title">{% trans "Gestion de la liste de votant·e·s" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<div class="level-item is-hidden-touch">
|
||||
{% if election.sent_mail is False %}
|
||||
<div class="level-item">
|
||||
<a class="button is-light is-outlined is-primary" href="{% url 'election.mail-voters' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-envelope-open"></i>
|
||||
</span>
|
||||
<span>{% trans "Envoyer le mail d'annonce" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% elif election.sent_mail is None %}
|
||||
<div class="level-item">
|
||||
<a class="button is-light is-outlined is-warning" href="javascript:location.reload();">
|
||||
<span class="icon">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</span>
|
||||
<span>{% trans "Mail en cours de distribution" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="level-item">
|
||||
<span class="button is-light is-outlined is-success">
|
||||
<span class="icon">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>{% trans "Mail envoyé" %}</span>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="level-item">
|
||||
<a class="button is-primary" href="{% url 'election.admin' election.pk %}">
|
||||
|
@ -73,6 +69,31 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-item is-hidden-desktop">
|
||||
{% if election.sent_mail is False %}
|
||||
<a class="button is-light is-outlined is-primary" href="{% url 'election.mail-voters' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-envelope-open"></i>
|
||||
</span>
|
||||
<span>{% trans "Envoyer le mail d'annonce" %}</span>
|
||||
</a>
|
||||
{% elif election.sent_mail is None %}
|
||||
<a class="button is-light is-outlined is-warning" href="javascript:location.reload();">
|
||||
<span class="icon">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</span>
|
||||
<span>{% trans "Mail en cours de distribution" %}</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="button is-light is-outlined is-success">
|
||||
<span class="icon">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>{% trans "Mail envoyé" %}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
{# Si on a déjà envoyé le mail avec les identifiants, on ne peut plus changer la liste #}
|
||||
|
@ -122,7 +143,7 @@
|
|||
<hr>
|
||||
|
||||
<div class="columns is-centered">
|
||||
<div class="column">
|
||||
<div class="column is-12">
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-bordered is-striped has-text-centered">
|
||||
<thead>
|
||||
|
|
|
@ -2,11 +2,60 @@
|
|||
{% load i18n markdown %}
|
||||
|
||||
|
||||
{% block custom_js %}
|
||||
{% if can_delete %}
|
||||
<script>
|
||||
_$('.modal-button').forEach(b => {
|
||||
b.addEventListener('click', () => {
|
||||
const f = _$('form', _id(b.dataset.target), false);
|
||||
f.dataset.target = b.dataset.origin;
|
||||
_$('[name="delete"]', f, false).value = 'non';
|
||||
});
|
||||
});
|
||||
|
||||
_$('form').forEach(f => {
|
||||
f.addEventListener('submit', event => {
|
||||
event.preventDefault();
|
||||
|
||||
if (_$('[name="delete"]', f, false).value == 'oui') {
|
||||
_get(f.action, r => {
|
||||
if (r.success && r.action == 'delete') {
|
||||
{% if election.restricted %}
|
||||
const r = _id(f.dataset.target);
|
||||
_$('.modal-button', r, false).remove();
|
||||
const i = _$('.fas', r, false);
|
||||
i.classList.remove('fa-check');
|
||||
i.classList.add('fa-times');
|
||||
{% else %}
|
||||
_id(f.dataset.target).remove()
|
||||
{% endif %}
|
||||
|
||||
// On ferme le modal
|
||||
document.documentElement.classList.remove('is-clipped');
|
||||
_id(f.dataset.modal).classList.remove('is-active');
|
||||
}
|
||||
|
||||
if (r.message) {
|
||||
_notif(r.message.content, r.message.class);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
document.documentElement.classList.remove('is-clipped');
|
||||
_id(f.dataset.modal).classList.remove('is-active');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="level">
|
||||
<div class="level is-mobile">
|
||||
{# Titre de l'élection #}
|
||||
<div class="level-left is-flex-shrink-1">
|
||||
<div class="level-left is-flex-shrink-1 mr-3">
|
||||
<h1 class="title">{{ election.name }}</h1>
|
||||
</div>
|
||||
|
||||
|
@ -47,7 +96,7 @@
|
|||
</div>
|
||||
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-two-thirds">
|
||||
<div class="column is-narrow">
|
||||
{% if can_delete %}
|
||||
{% include "forms/modal-form.html" with modal_id="delete" form=d_form %}
|
||||
{% endif %}
|
||||
|
@ -62,23 +111,43 @@
|
|||
{% endif %}
|
||||
<tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% if election.restricted %}
|
||||
{% for v in election.registered_voters.all %}
|
||||
<tr>
|
||||
<tr id="v_{{ forloop.counter }}">
|
||||
<td>{{ v.full_name }} ({{ v.base_username }})</td>
|
||||
{% if v in voters %}
|
||||
<td class="has-text-centered">
|
||||
<span class="icon">
|
||||
{% if v in voters %}
|
||||
<i class="fas fa-check"></i>
|
||||
{% else %}
|
||||
<i class="fas fa-times"></i>
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
{% if can_delete %}
|
||||
<td class="has-text-centered">
|
||||
{% blocktrans with v_name=v.full_name asvar v_delete %}Supprimer le vote de {{ v_name }}{% endblocktrans %}
|
||||
<a class="tag is-danger modal-button delete-vote" data-target="modal-delete" data-post_url="{% url 'election.delete-vote' election.pk v.pk forloop.counter %}" data-title="{{ v_delete }}" data-origin="v_{{ forloop.counter }}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-user-minus"></i>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<td class="has-text-centered">
|
||||
<span class="icon">
|
||||
<i class="fas fa-times"></i>
|
||||
</span>
|
||||
</td>
|
||||
{% if can_delete %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% for v in voters %}
|
||||
<tr id="v_{{ forloop.counter }}">
|
||||
<td>{{ v.full_name }} ({{ v.base_username }})</td>
|
||||
|
@ -90,11 +159,12 @@
|
|||
{% if can_delete %}
|
||||
<td class="has-text-centered">
|
||||
{% blocktrans with v_name=v.full_name asvar v_delete %}Supprimer le vote de {{ v_name }}{% endblocktrans %}
|
||||
<a class="tag is-danger has-tooltip-primary modal-button delete-vote" data-target="modal-delete" data-tooltip="{{ v_delete }}" data-post_url="{% url 'election.delete-vote' election.pk v.pk forloop.counter %}" data-title="{{ v_delete }}">
|
||||
<a class="tag is-danger modal-button delete-vote" data-target="modal-delete" data-post_url="{% url 'election.delete-vote' election.pk v.pk forloop.counter %}" data-title="{{ v_delete }}" data-origin="v_{{ forloop.counter }}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-user-minus"></i>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -214,7 +214,43 @@ class ElectionUpdateView(CreatorOnlyEditMixin, SuccessMessageMixin, UpdateView):
|
|||
return super().form_valid(form)
|
||||
|
||||
|
||||
class DeleteVoteView(ClosedElectionMixin, FormView):
|
||||
class DeleteVoteView(ClosedElectionMixin, JsonDeleteView):
|
||||
model = Election
|
||||
|
||||
def get_message(self):
|
||||
return {
|
||||
"content": _("Vote de {} supprimé !").format(self.voter.full_name),
|
||||
"class": "success",
|
||||
}
|
||||
|
||||
@transaction.atomic
|
||||
def get(self, request, *args, **kwargs):
|
||||
election = self.get_object()
|
||||
self.voter = User.objects.get(pk=self.kwargs["user_pk"])
|
||||
|
||||
# On envoie un mail à la personne lui indiquant que le vote est supprimé
|
||||
EmailMessage(
|
||||
subject="Vote removed",
|
||||
body=MAIL_VOTE_DELETED.format(
|
||||
full_name=self.voter.full_name,
|
||||
election_name=election.name,
|
||||
),
|
||||
to=[self.voter.email],
|
||||
).send()
|
||||
|
||||
# On supprime les votes
|
||||
Vote.objects.filter(
|
||||
user=self.voter,
|
||||
option__question__election=election,
|
||||
).delete()
|
||||
|
||||
# On marque les questions comme non votées
|
||||
self.voter.cast_elections.remove(election)
|
||||
self.voter.cast_questions.remove(*list(election.questions.all()))
|
||||
return self.render_to_json(action="delete")
|
||||
|
||||
|
||||
class DeleteVoteViewa(ClosedElectionMixin, FormView):
|
||||
model = Election
|
||||
template_name = "elections/delete_vote.html"
|
||||
form_class = DeleteVoteForm
|
||||
|
@ -453,8 +489,7 @@ class ElectionVotersView(NotArchivedMixin, DetailView):
|
|||
|
||||
if user.is_authenticated:
|
||||
can_delete = (
|
||||
not election.restricted
|
||||
and election.created_by == user
|
||||
election.created_by == user
|
||||
and election.end_date < timezone.now()
|
||||
and not election.tallied
|
||||
)
|
||||
|
|
|
@ -10577,6 +10577,7 @@ body {
|
|||
height: auto;
|
||||
min-height: 2em;
|
||||
white-space: unset;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.message.is-primary .message-body hr {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -36,6 +36,7 @@ body
|
|||
height: auto
|
||||
min-height: 2em
|
||||
white-space: unset
|
||||
text-align: center
|
||||
|
||||
.message
|
||||
&.is-primary
|
||||
|
|
|
@ -150,7 +150,7 @@
|
|||
</div>
|
||||
|
||||
<div class="dropdown-menu pr-1">
|
||||
<div class="dropdown-content">
|
||||
<div class="dropdown-content pb-0">
|
||||
<a class="dropdown-item" href="{% url 'election.list' %}">
|
||||
<span class="icon is-size-5 mr-3">
|
||||
<i class="fas fa-vote-yea"></i>
|
||||
|
@ -200,14 +200,14 @@
|
|||
|
||||
{% for lang in langs %}
|
||||
{% with lang_svg="images/"|add:lang.code|add:".svg" %}
|
||||
<hr class="dropdown-divider">
|
||||
<hr class="dropdown-divider {% if forloop.first %}mb-0{% else %}my-0{% endif %}">
|
||||
|
||||
<a class="dropdown-item lang-selector" data-lang="{{ lang.code }}">
|
||||
<span class="icon-text">
|
||||
<span class="icon mr-4" style="border-radius:3px">
|
||||
<span class="icon mr-4">
|
||||
<img style="border-radius:3px" src="{% static lang_svg %}">
|
||||
</span>
|
||||
<span class="is-size-5">{{ lang.name_translated }}</span>
|
||||
<span class="is-size-">{{ lang.name_translated }}</span>
|
||||
</span>
|
||||
{% endwith %}
|
||||
</a>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="modal" id="modal-{{ modal_id }}">
|
||||
<div class="modal-background" data-closes="modal-{{ modal_id }}"></div>
|
||||
<div class="modal-card">
|
||||
<form method="post" action="{{ post_url }}">
|
||||
<form method="post" action="{{ post_url }}" data-modal="modal-{{ modal_id }}">
|
||||
{% csrf_token %}
|
||||
|
||||
<header class="modal-card-head">
|
||||
|
|
Loading…
Reference in a new issue