Tweaks on templates and foundation for uploading a file

This commit is contained in:
Tom Hubrecht 2020-12-22 01:17:38 +01:00
parent e7db47116e
commit 5c7e2238d8
9 changed files with 140 additions and 18 deletions

View file

@ -24,6 +24,10 @@ class ElectionForm(forms.ModelForm):
fields = ["name", "description", "restricted", "start_date", "end_date"] fields = ["name", "description", "restricted", "start_date", "end_date"]
class UploadVotersForm(forms.Form):
csv_file = forms.FileField(label=_("Sélectionnez un fichier .csv"))
class QuestionForm(forms.ModelForm): class QuestionForm(forms.ModelForm):
class Meta: class Meta:
model = Question model = Question

View file

@ -22,9 +22,9 @@
</div> </div>
<div class="level-right"> <div class="level-right">
{% if election.start_date > current_time %}
{# Lien pour la modification #} {# Lien pour la modification et l'upload des votant·e·s #}
{% if election.start_date > current_time %}
<div class="level-item"> <div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.update' election.pk %}"> <a class="button is-light is-outlined is-primary" href="{% url 'election.update' election.pk %}">
<span class="icon"> <span class="icon">
@ -33,10 +33,22 @@
<span>{% trans "Modifier" %}</span> <span>{% trans "Modifier" %}</span>
</a> </a>
</div> </div>
{% if election.restricted %}
<div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.upload-voters' election.pk %}">
<span class="icon">
<i class="fas fa-file-import"></i>
</span>
<span>{% trans "Importer une liste de votant·e·s" %}</span>
</a>
</div>
{% endif %}
{% elif election.end_date < current_time %} {% elif election.end_date < current_time %}
{% if not election.tallied %}
{# Lien pour le dépouillement #} {# Lien pour le dépouillement #}
{% if not election.tallied %}
<div class="level-item"> <div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.tally' election.pk %}"> <a class="button is-light is-outlined is-primary" href="{% url 'election.tally' election.pk %}">
<span class="icon"> <span class="icon">
@ -45,9 +57,9 @@
<span>{% trans "Dépouiller" %}</span> <span>{% trans "Dépouiller" %}</span>
</a> </a>
</div> </div>
{% else %}
{# Lien pour la publication des résultats #} {# Lien pour la publication des résultats #}
{% else %}
<div class="level-item"> <div class="level-item">
<a class="button is-outlined is-primary" href="{% url 'election.publish' election.pk %}"> <a class="button is-outlined is-primary" href="{% url 'election.publish' election.pk %}">
<span class="icon"> <span class="icon">

View file

@ -0,0 +1,60 @@
{% extends "base.html" %}
{% load i18n %}
{% block extra_head %}
<script>
$(document).ready(function($) {
const fileInput = document.querySelector('#import-voters input[type=file]');
fileInput.onchange = () => {
if (fileInput.files.length > 0) {
const fileName = document.querySelector('#import-voters .file-name');
fileName.textContent = fileInput.files[0].name;
}
}
});
</script>
{% endblock %}
{% block content %}
<h1 class="title">{% trans "Importer une liste de votant·e·s" %}</h1>
<hr>
<div class="message is-warning">
<div class="message-body">
{% trans "Importez un fichier au format CSV, avec sur la première colonne les prénoms, sur la deuxième le nom et la troisième l'adresse email. Soit :<br><br><pre>Prénom_1,Nom_1,mail_1@machin.test<br>Prénom_2,Nom_2,mail_2@bidule.test<br>...</pre>" %}
</div>
</div>
<div class="columns is-centered">
<div class="column is-two-thirds">
<form action="" method="post" id="import-voters">
{% csrf_token %}
{% include "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">
<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 %}">
<span class="icon is-small">
<i class="fas fa-undo-alt"></i>
</span>
<span>{% trans "Retour" %}</span>
</a>
</div>
</div>
</form>
</div>
</div>
{% endblock %}

View file

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

View file

@ -10,12 +10,19 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import ( from django.views.generic import (
CreateView, CreateView,
DetailView, DetailView,
FormView,
ListView, ListView,
RedirectView, RedirectView,
UpdateView, UpdateView,
) )
from .forms import ElectionForm, OptionForm, OptionFormSet, QuestionForm from .forms import (
ElectionForm,
OptionForm,
OptionFormSet,
QuestionForm,
UploadVotersForm,
)
from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnlyMixin from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnlyMixin
from .models import Election, Option, Question from .models import Election, Option, Question
@ -63,11 +70,13 @@ class ElectionCreateView(SuccessMessageMixin, CreateView):
return super().form_valid(form) return super().form_valid(form)
# TODO : only the creator can edit the election and view the admin panel
class ElectionAdminView(CreatorOnlyMixin, DetailView): class ElectionAdminView(CreatorOnlyMixin, DetailView):
model = Election model = Election
template_name = "elections/election_admin.html" template_name = "elections/election_admin.html"
def get_next_url(self):
return reverse("election.view", args=[self.object.pk])
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs.update({"current_time": timezone.now()}) kwargs.update({"current_time": timezone.now()})
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@ -76,6 +85,19 @@ class ElectionAdminView(CreatorOnlyMixin, DetailView):
return super().get_queryset().prefetch_related("questions__options") return super().get_queryset().prefetch_related("questions__options")
class ElectionUploadVotersView(CreatorOnlyEditMixin, FormView):
model = Election
form_class = UploadVotersForm
template_name = "elections/upload_voters.html"
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
def form_valid(self, form):
pass
class ElectionListView(CreatorOnlyMixin, ListView): class ElectionListView(CreatorOnlyMixin, ListView):
model = Election model = Election
template_name = "elections/election_list.html" template_name = "elections/election_list.html"
@ -290,7 +312,7 @@ class VoteView(OpenElectionOnlyMixin, DetailView):
model = Question model = Question
template_name = "elections/vote.html" template_name = "elections/vote.html"
def get_newt_url(self): def get_next_url(self):
return reverse("election.view", args=[self.object.election.pk]) return reverse("election.view", args=[self.object.election.pk])
def get_success_url(self): def get_success_url(self):

View file

@ -94,6 +94,8 @@ class LogoutView(auth_views.LogoutView):
logged in via CAS. logged in via CAS.
""" """
template_name = "auth/logout.html"
def setup(self, request): def setup(self, request):
super().setup(request) super().setup(request)
if "CASCONNECTED" in request.session: if "CASCONNECTED" in request.session:

View file

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% load i18n %}
{% block auth %}{% endblock %}
{% block content %}
<h1 class="title">{% trans "Vous avez bien été déconnecté." %}</h1>
<hr>
{% endblock %}

View file

@ -55,7 +55,7 @@
</div> </div>
<div class="level-item ml-3"> <div class="level-item ml-3">
<a class="icon is-size-1 has-text-white" href="{% url 'auth.logout' %}?next=/{{ view.get_next_url }}"> <a class="icon is-size-1 has-text-white" href="{% url 'auth.logout' %}?next={% if view.get_next_url %}{{ view.get_next_url }}{% else %}/{% endif %}">
<i class="fas fa-sign-out-alt"></i> <i class="fas fa-sign-out-alt"></i>
</a> </a>
</div> </div>

View file

@ -1,22 +1,27 @@
{% load bulma_utils i18n %} {% load bulma_utils i18n %}
<label class="label {% if field.field.required %}{{ form.required_css_class }}{% endif %}"> <label class="label {% if field.field.required %}{{ form.required_css_class }}{% endif %}">
{{ field.label }} {{ field.label_tag }}
</label> </label>
<div class="control"> <div class="control">
<label class="file-label"> <div class="file has-name">
{{ field|bulmafy:'file-input' }} <label class="file-label">
<span class="file-cta"> {{ field|bulmafy:'file-input' }}
<span class="file-icon"> <span class="file-cta">
<i class="fas fa-upload"></i> <span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
{% trans "Choisissez un fichier..." %}
</span>
</span> </span>
<span class="file-label"> <span class="file-name">
{% trans "Choisissez un fichier..." %} {% trans "Aucun fichier sélectionné" %}
</span> </span>
</span> </label>
</label> </div>
{% for error in field.errors %} {% for error in field.errors %}
<span class="help is-danger {{ form.error_css_class }}">{{ error }}</span> <span class="help is-danger {{ form.error_css_class }}">{{ error }}</span>