Liste des élections créées

This commit is contained in:
Tom Hubrecht 2020-12-19 23:48:18 +01:00
parent 42bf59bf1a
commit 9281c76ddc
9 changed files with 243 additions and 130 deletions

View file

@ -0,0 +1,16 @@
# TODO:
class CreatorOnlyMixin:
"""Restreint l'accès au créateurice de l'élection"""
def get_queryset(self):
# TODO: change the way we collect the user according to the model used
user = self.request.user
return super().get_queryset().filter(created_by=user)
class AdministratorOnlyMixin:
"""Restreint l'accès aux admins"""
class VoterOnlyMixin:
"""Restreint l'accès aux voteureuses de l'élection"""

View file

@ -23,6 +23,9 @@ class Election(models.Model):
archived = models.BooleanField(_("archivée"), default=False)
class Meta:
ordering = ["-start_date", "-end_date"]
class Question(models.Model):
election = models.ForeignKey(
@ -34,6 +37,9 @@ class Question(models.Model):
_("nombre maximal de votes reçus"), default=0
)
class Meta:
ordering = ["id"]
class Option(models.Model):
question = models.ForeignKey(
@ -46,3 +52,6 @@ class Option(models.Model):
)
# For now, we store the amount of votes received after the election is tallied
nb_votes = models.PositiveSmallIntegerField(_("nombre de votes reçus"), default=0)
class Meta:
ordering = ["id"]

View file

@ -38,14 +38,16 @@
<body>
<nav class="level has-background-primary">
<div class="level-left pl-4">
<div class="level-item">
<h1 class="has-text-primary-light is-size-1 is-family-secondary">Kadenios</h1>
</div>
<div class="level-right pr-4">
<figure class="image is-64x64">
<a href="">
<img src="{% static "images/logout.svg" %}" alt="logout">
</div>
<div class="level-right pr-5">
<div class="level-item">
<a class="icon is-size-1 has-text-white" href="">
<i class="fas fa-sign-out-alt"></i>
</a>
</figure>
</div>
</div>
</nav>
{% block layout %}

View file

@ -22,54 +22,56 @@
</div>
<div class="level-right">
<div class="level-item">
{% if election.start_date > current_time %}
{# Lien pour la modification #}
<div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.update' election.pk %}">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
&nbsp;
{% trans "Modifier" %}
<span>{% trans "Modifier" %}</span>
</a>
</div>
{% elif election.end_date < current_time %}
{% if not election.tallied %}
{# Lien pour le dépouillement #}
<div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.tally' election.pk %}">
<span class="icon">
<i class="fas fa-poll-h"></i>
</span>
&nbsp;
{% trans "Dépouiller" %}
<span>{% trans "Dépouiller" %}</span>
</a>
</div>
{% else %}
{# Lien pour la publication des résultats #}
<div class="level-item">
<a class="button is-outlined is-primary" href="{% url 'election.publish' election.pk %}">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
&nbsp;
{% if not election.results_public %}
{% trans "Publier" %}
<span>{% trans "Publier" %}</span>
{% else %}
{% trans "Dépublier" %}
<span>{% trans "Dépublier" %}</span>
{% endif %}
</a>&nbsp;
</a>
</div>
{# Lien pour l'archivage #}
<div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.archive' election.pk %}">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
&nbsp;
{% trans "Archiver" %}
<span>{% trans "Archiver" %}</span>
</a>
{% endif %}
{% endif %}
</div>
{% endif %}
{% endif %}
</div>
</div>
<hr>
@ -79,26 +81,23 @@
<div class="message-body">{{ election.description|linebreaksbr }}</div>
</div>
<div class="container">
{# Liste des questions #}
{% for q in election.questions.all %}
<div class="panel">
{# Liste des questions #}
{% for q in election.questions.all %}
<div class="panel">
<div class="panel-heading is-size-6">
{{ q.text }}
<span>{{ q.text }}</span>
{% if election.start_date > current_time %}
&nbsp;
<a class="tag is-small is-outlined is-light is-danger">
<span class="icon">
<i class="fas fa-times"></i>
</span>
{% trans "Supprimer" %}
<span>{% trans "Supprimer" %}</span>
</a>
<a class="tag is-small is-outlined is-light is-info">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
{% trans "Modifier" %}
<span>{% trans "Modifier" %}</span>
</a>
{% endif %}
</div>
@ -123,8 +122,8 @@
<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>&nbsp;
{{ o.nb_votes }}
</span>
<span>{{ o.nb_votes }}</span>
</span>&nbsp;&nbsp;
{% endif %}
{{ o.text }}
@ -149,12 +148,12 @@
</div>
</form>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
{# Rajout d'une question #}
{% if election.start_date > current_time %}
<div class="columns is-centered">
{# Rajout d'une question #}
{% if election.start_date > current_time %}
<div class="columns is-centered">
<div class="column is-two-thirds">
<form action="" method="POST">
{% csrf_token %}
@ -172,8 +171,7 @@
</div>
</form>
</div>
</div>
{% endif %}
</div>
{% endif %}
{% endblock %}

View file

@ -31,8 +31,7 @@
<h1 class="title">{% trans "Création d'une élection" %}</h1>
<hr>
<div class="container">
<form action="" method="post">
<form action="" method="post">
{% csrf_token %}
{% include "elections/forms/form.html" with errors=False %}
@ -42,7 +41,6 @@
<button class="button is-fullwidth is-outlined is-primary is-light">{% trans "Enregistrer" %}</button>
</div>
</div>
</form>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,65 @@
{% extends "elections/base.html" %}
{% load i18n %}
{% block content %}
<div class="level">
<div class="level-left">
<div class="level-item">
<h1 class="title">{% trans "Liste des élections créées" %}</h1>
</div>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-light is-outlined is-primary" href={% url 'election.create' %}>
<span class="icon">
<i class="fas fa-plus"></i>
</span>
<span>{% trans "Créer une élection" %}</span>
</a>
</div>
</div>
</div>
<hr>
{% for e in election_list %}
<div class="message is-primary">
<div class="message-header is-size-6 is-radiusless">
<div>
<span class="mr-2">{{ e.name }}</span>
<span class="tag is-primary is-light">{{ e.start_date|date:"d/m/Y H:i" }}</span>
<span class="icon has-text-primary-light">
<i class="fas fa-long-arrow-alt-right"></i>
</span>
<span class="tag is-primary is-light">{{ e.end_date|date:"d/m/Y H:i" }}</span>
{% if e.tallied %}
&nbsp;
<span class="tag is-success is-light">{% trans "Élection dépouillée" %}</span>
{% endif %}
{% if e.results_public %}
&nbsp;
<span class="tag is-info is-light">{% trans "Élection publiée" %}</span>
{% endif %}
{% if e.archived %}
&nbsp;
<span class="tag is-danger is-light">{% trans "Élection archivée" %}</span>
{% endif %}
</div>
<a class="has-text-primary-light" href="{% url 'election.admin' e.pk %}">
<span class="icon">
<i class="fas fa-tools"></i>
</span>
<span>{% trans "" %}</span>
</a>
</div>
<p class="message-body">
{{ e.description|linebreaksbr }}
</p>
</div>
{% endfor %}
{% endblock %}

View file

@ -31,21 +31,29 @@
<h1 class="title">{% trans "Modification d'une élection" %}</h1>
<hr>
<div class="container">
<form action="" method="post">
<form action="" method="post">
{% csrf_token %}
{% include "elections/forms/form.html" with errors=False %}
<div class="field is-grouped is-centered">
<div class="control is-expanded">
<button class="button is-fullwidth is-outlined is-primary is-light">{% trans "Enregistrer" %}</button>
<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.admin' election.pk %}">{% trans "Retour" %}</a>
<a class="button is-primary" href="{% url 'election.admin' election.pk %}">
<span class="icon is-small">
<i class="fas fa-undo-alt"></i>
</span>
<span>{% trans "Retour" %}</span>
</a>
</div>
</div>
</form>
</div>
</form>
{% endblock %}

View file

@ -4,6 +4,7 @@ from . import views
urlpatterns = [
path("create/", views.ElectionCreateView.as_view(), name="election.create"),
path("created/", views.ElectionListView.as_view(), name="election.created"),
path("admin/<int:pk>", views.ElectionAdminView.as_view(), name="election.admin"),
path("update/<int:pk>", views.ElectionUpdateView.as_view(), name="election.update"),
path("tally/<int:pk>", views.ElectionTallyView.as_view(), name="election.tally"),

View file

@ -6,14 +6,25 @@ from django.urls import reverse
from django.utils import timezone
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, RedirectView, UpdateView
from django.views.generic import (
CreateView,
DetailView,
ListView,
RedirectView,
UpdateView,
)
from django.views.generic.detail import SingleObjectMixin
from .forms import ElectionCreateForm, OptionFormSet
from .mixins import CreatorOnlyMixin
from .models import Election, Option, Question
# TODO: access control *everywhere*
# #############################################################################
# Administration Views
# #############################################################################
class ElectionCreateView(SuccessMessageMixin, CreateView):
model = Election
@ -35,7 +46,7 @@ class ElectionCreateView(SuccessMessageMixin, CreateView):
# TODO : only the creator can edit the election and view the admin panel
class ElectionAdminView(DetailView):
class ElectionAdminView(CreatorOnlyMixin, DetailView):
model = Election
template_name = "elections/election_admin.html"
@ -47,6 +58,11 @@ class ElectionAdminView(DetailView):
return super().get_queryset().prefetch_related("questions__options")
class ElectionListView(CreatorOnlyMixin, ListView):
model = Election
template_name = "elections/election_list.html"
class ElectionUpdateView(SuccessMessageMixin, UpdateView):
model = Election
fields = ["name", "description", "start_date", "end_date"]