Template changes and vote restriction for open elections
This commit is contained in:
parent
5f1fed991b
commit
9faa0b3354
6 changed files with 134 additions and 61 deletions
|
@ -35,6 +35,22 @@ class RestrictAccessMixin(SelectElectionMixin):
|
|||
return qs.none()
|
||||
|
||||
|
||||
class OpenElectionOnly(RestrictAccessMixin):
|
||||
"""N'autorise la vue que lorsque l'élection est ouverte"""
|
||||
|
||||
def get_filters(self):
|
||||
f_prefix = self.get_f_prefix()
|
||||
# On ne peut modifier que les élections qui n'ont pas commencé, et
|
||||
# accessoirement qui ne sont pas dépouillées ou archivées
|
||||
# TODO: décider si on choisit pas de juste garder les dates d'ouverture
|
||||
filters = super().get_filters()
|
||||
filters[f_prefix + "start_date__lt"] = timezone.now()
|
||||
filters[f_prefix + "end_date__gt"] = timezone.now()
|
||||
filters[f_prefix + "tallied"] = False
|
||||
filters[f_prefix + "archived"] = False
|
||||
return filters
|
||||
|
||||
|
||||
class CreatorOnlyMixin(RestrictAccessMixin):
|
||||
"""Restreint l'accès au créateurice de l'élection"""
|
||||
|
||||
|
|
|
@ -4,23 +4,74 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
<h1 class="title">{{ election.name }}</h1>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
{# Titre de l'élection #}
|
||||
<div class="level-item">
|
||||
<h1 class="title">{{ election.name }}</h1>
|
||||
</div>
|
||||
|
||||
{# Dates d'ouverture de l'élection #}
|
||||
<div class="level-item">
|
||||
<span class="tag is-medium is-primary">{{ election.start_date|date:"d/m/Y H:i" }}</span>
|
||||
<span class="icon">
|
||||
<i class="fas fa-long-arrow-alt-right"></i>
|
||||
</span>
|
||||
<span class="tag is-medium is-primary">{{ election.end_date|date:"d/m/Y H:i" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if election.start_date < current_time %}
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<span class="tag is-medium is-outlined is-light is-primary">
|
||||
{% if election.end_date < current_time %}
|
||||
{% trans "Élection terminée" %}
|
||||
{% else %}
|
||||
{% trans "Élection en cours" %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="message is-info">
|
||||
<p class="message-body">{{ election.description }}</p>
|
||||
{# Description de l'élection #}
|
||||
<div class="message is-primary">
|
||||
<div class="message-body">{{ election.description|linebreaksbr }}</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
{% for q in questions %}
|
||||
<div class="box">
|
||||
<h3 class="subtitle">{{ q.text }}</h3>
|
||||
{# Liste des questions #}
|
||||
{% for q in election.questions.all %}
|
||||
<div class="panel" id="q_{{ q.pk }}">
|
||||
<div class="panel-heading is-size-6">
|
||||
{% if election.start_date < current_time and election.end_date > current_time %}
|
||||
<a class="tag is-small is-outlined is-light is-danger" href="{% url 'election.vote' q.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-vote-yea"></i>
|
||||
</span>
|
||||
<span>{% trans "Voter" %}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<span class="ml-2">{{ q.text }}</span>
|
||||
</div>
|
||||
|
||||
{# Liste des options possibles #}
|
||||
{% for o in q.options.all %}
|
||||
{{ o.text }}<br>
|
||||
{% endfor %}
|
||||
<a class="button is-outlined is-info is-light">{% trans "Voter" %}</a>
|
||||
<div class="panel-block">
|
||||
{% if election.tallied and election.results_public %}
|
||||
<span class="tag {% if o.nb_votes == q.max_votes %}is-success{% else %}is-primary{% endif %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-vote-yea"></i>
|
||||
</span>
|
||||
<span>{{ o.nb_votes }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="ml-2">{{ o.text }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -117,16 +117,16 @@
|
|||
<i class="fas fa-edit"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% elif election.tallied %}
|
||||
<span class="tag {% if o.nb_votes == q.max_votes %}is-success{% else %}is-primary{% endif %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-vote-yea"></i>
|
||||
</span>
|
||||
<span>{{ o.nb_votes }}</span>
|
||||
</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
{{ o.text }}
|
||||
<span class="ml-2">{{ o.text }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
|
@ -160,13 +160,13 @@
|
|||
|
||||
<div class="field has-addons">
|
||||
<div class="control has-icons-left is-expanded">
|
||||
<input class="input" type="text" name="text" id="id_text" placeholder="{% trans "Rajouter une question" %}">
|
||||
<input class="input is-primary" type="text" name="text" id="id_text" placeholder="{% trans "Rajouter une question" %}">
|
||||
<span class="icon is-left">
|
||||
<i class="fas fa-question"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button">{% trans "Valider" %}</button>
|
||||
<button class="button is-primary is-outlined">{% trans "Valider" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="title">{% trans "Liste des élections créées" %}</h1>
|
||||
<h1 class="title">{% trans "Liste des élections créées" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
|
@ -35,18 +35,15 @@
|
|||
<span class="tag is-primary is-light">{{ e.end_date|date:"d/m/Y H:i" }}</span>
|
||||
|
||||
{% if e.tallied %}
|
||||
|
||||
<span class="tag is-success is-light">{% trans "Élection dépouillée" %}</span>
|
||||
<span class="tag is-success is-light ml-3">{% trans "Élection dépouillée" %}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if e.results_public %}
|
||||
|
||||
<span class="tag is-info is-light">{% trans "Élection publiée" %}</span>
|
||||
<span class="tag is-info is-light ml-3">{% trans "Élection publiée" %}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if e.archived %}
|
||||
|
||||
<span class="tag is-danger is-light">{% trans "Élection archivée" %}</span>
|
||||
<span class="tag is-danger is-light ml-3">{% trans "Élection archivée" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<a class="has-text-primary-light" href="{% url 'election.admin' e.pk %}">
|
||||
|
|
|
@ -4,20 +4,36 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
<h1 class="title">{% trans "Vote pour la question :" %} {{ question }}</h1>
|
||||
<h1 class="title">{% trans "Vote pour la question :" %} {{ question.text }}</h1>
|
||||
<hr>
|
||||
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-two-thirds">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% include "elections/forms/formset.html" %}
|
||||
|
||||
<div class="field">
|
||||
<p class="control">
|
||||
<input class="button is-fullwidth" type="submit" value="Enregistrer">
|
||||
</p>
|
||||
<div class="field is-grouped is-centered">
|
||||
<div class="control is-expanded">
|
||||
<button class="button is-fullwidth is-outlined is-primary is-light">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-check"></i>
|
||||
</span>
|
||||
<span>{% trans "Enregistrer" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-primary" href="{% url 'election.view' question.election.pk %}">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-undo-alt"></i>
|
||||
</span>
|
||||
<span>{% trans "Retour" %}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.db.models import Count, Prefetch
|
||||
|
||||
# from django.db.models import Count, Prefetch
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
@ -15,7 +16,7 @@ from django.views.generic import (
|
|||
)
|
||||
|
||||
from .forms import ElectionForm, OptionForm, OptionFormSet, QuestionForm
|
||||
from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin
|
||||
from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnly
|
||||
from .models import Election, Option, Question
|
||||
|
||||
# TODO: access control *everywhere*
|
||||
|
@ -265,38 +266,30 @@ class ElectionView(DetailView):
|
|||
template_name = "elections/election.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if self.object.tallied:
|
||||
options_qs = Option.objects.annotate(nb_votes=Count("voters"))
|
||||
questions = self.election.question.prefetch_related(
|
||||
Prefetch("options", queryset=options_qs)
|
||||
)
|
||||
context["questions"] = questions
|
||||
|
||||
return context
|
||||
kwargs.update({"current_time": timezone.now()})
|
||||
return super().get_context_data(**kwargs)
|
||||
# context = super().get_context_data(**kwargs)
|
||||
# if self.object.tallied:
|
||||
# options_qs = Option.objects.annotate(nb_votes=Count("voters"))
|
||||
# questions = self.election.question.prefetch_related(
|
||||
# Prefetch("options", queryset=options_qs)
|
||||
# )
|
||||
# context["questions"] = questions
|
||||
# return context
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(archived=False)
|
||||
|
||||
|
||||
class VoteView(SuccessMessageMixin, DetailView):
|
||||
model = Question
|
||||
template_name = "elections/vote.html"
|
||||
|
||||
def get_queryset(self):
|
||||
# On ne peut voter que si l'élection n'a pas été comptée
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.filter(
|
||||
election__tallied=False,
|
||||
election__archived=False,
|
||||
election__start_date__lt=timezone.now(),
|
||||
election__end_date__gt=timezone.now(),
|
||||
)
|
||||
.select_related("election")
|
||||
.filter(archived=False)
|
||||
.prefetch_related("questions__options")
|
||||
)
|
||||
|
||||
|
||||
class VoteView(OpenElectionOnly, SuccessMessageMixin, DetailView):
|
||||
model = Question
|
||||
template_name = "elections/vote.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
vote_form = OptionFormSet(instance=self.object)
|
||||
|
|
Loading…
Reference in a new issue