Rajoute un lien pour exporter la liste des votant·e·s en csv

This commit is contained in:
Tom Hubrecht 2021-04-15 23:00:10 +02:00
parent 9d316a3044
commit 3c7598ffe4
5 changed files with 98 additions and 63 deletions

View file

@ -28,7 +28,6 @@
<h1 class="title">{{ election.name }}</h1> <h1 class="title">{{ election.name }}</h1>
</div> </div>
{% if election.start_date > current_time or election.end_date < current_time %}
<div class="level-right"> <div class="level-right">
<div class="level-item"> <div class="level-item">
<div class="dropdown is-right"> <div class="dropdown is-right">
@ -45,6 +44,14 @@
<div class="dropdown-menu" id="dropdown-menu" role="menu"> <div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content"> <div class="dropdown-content">
{# Téléchargement de la liste des votant·e·s #}
<a class="dropdown-item" href="{% url 'election.export-voters' election.pk %}">
<span class="icon">
<i class="fas fa-file-download"></i>
</span>
<span>{% trans "Exporter les votant·e·s" %}
</a>
{% if election.start_date > current_time %} {% if election.start_date > current_time %}
{# Modification de l'élection #} {# Modification de l'élection #}
<a class="dropdown-item" href="{% url 'election.update' election.pk %}"> <a class="dropdown-item" href="{% url 'election.update' election.pk %}">
@ -115,7 +122,6 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
<div class="level"> <div class="level">

View file

@ -16,6 +16,11 @@ urlpatterns = [
views.ElectionUploadVotersView.as_view(), views.ElectionUploadVotersView.as_view(),
name="election.upload-voters", name="election.upload-voters",
), ),
path(
"export-voters/<int:pk>",
views.ExportVotersView.as_view(),
name="election.export-voters",
),
path( path(
"delete-vote/<int:pk>/<int:user_pk>/<int:anchor>", "delete-vote/<int:pk>/<int:user_pk>/<int:anchor>",
views.DeleteVoteView.as_view(), views.DeleteVoteView.as_view(),

View file

@ -1,8 +1,10 @@
import csv
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django.db import transaction from django.db import transaction
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
@ -16,7 +18,9 @@ from django.views.generic import (
ListView, ListView,
RedirectView, RedirectView,
UpdateView, UpdateView,
View,
) )
from django.views.generic.detail import SingleObjectMixin
from .forms import ( from .forms import (
DeleteVoteForm, DeleteVoteForm,
@ -107,6 +111,22 @@ class ElectionAdminView(CreatorOnlyMixin, DetailView):
return super().get_queryset().prefetch_related("questions__options") return super().get_queryset().prefetch_related("questions__options")
class ExportVotersView(CreatorOnlyMixin, SingleObjectMixin, View):
model = Election
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type="text/csv")
writer = csv.writer(response)
response["Content-Disposition"] = "attachment; filename=voters.csv"
writer.writerow(["Nom", "login"])
for v in self.get_object().voters.all():
writer.writerow([v.full_name, v.username])
return response
class ElectionUploadVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormView): class ElectionUploadVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormView):
model = Election model = Election
form_class = UploadVotersForm form_class = UploadVotersForm

View file

@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.1\n" "Project-Id-Version: 0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-15 16:56+0200\n" "POT-Creation-Date: 2021-04-15 22:50+0200\n"
"PO-Revision-Date: 2021-04-15 16:57+0200\n" "PO-Revision-Date: 2021-04-15 22:55+0200\n"
"Last-Translator: Test Translator <test@translator>\n" "Last-Translator: Test Translator <test@translator>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: en\n" "Language: en\n"
@ -18,125 +18,125 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.4.1\n" "X-Generator: Poedit 2.4.1\n"
#: elections/forms.py:29 #: elections/forms.py:19
msgid "Impossible de faire débuter l'élection dans le passé" msgid "Impossible de faire débuter l'élection dans le passé"
msgstr "Impossible to start the election in the past" msgstr "Impossible to start the election in the past"
#: elections/forms.py:33 #: elections/forms.py:23
msgid "Impossible de terminer l'élection avant de la commencer" msgid "Impossible de terminer l'élection avant de la commencer"
msgstr "Impossible to end the election before it starts" msgstr "Impossible to end the election before it starts"
#: elections/forms.py:56 #: elections/forms.py:46
msgid "Sélectionnez un fichier .csv" msgid "Sélectionnez un fichier .csv"
msgstr "Select a .csv file" msgstr "Select a .csv file"
#: elections/forms.py:66 #: elections/forms.py:56
msgid "Extension de fichier invalide, il faut un fichier au format CSV." msgid "Extension de fichier invalide, il faut un fichier au format CSV."
msgstr "Invalid file extension, a CSV file is required." msgstr "Invalid file extension, a CSV file is required."
#: elections/forms.py:100 #: elections/forms.py:90
msgid "Supprimer le vote de {} ({}) ?" msgid "Supprimer le vote de {} ({}) ?"
msgstr "Delete the vote of {} ({}) ?" msgstr "Delete the vote of {} ({}) ?"
#: elections/forms.py:105 elections/templates/elections/election_admin.html:168 #: elections/forms.py:95 elections/templates/elections/election_admin.html:174
#: elections/templates/elections/election_admin.html:195 #: elections/templates/elections/election_admin.html:201
#: elections/templates/elections/election_voters.html:57 #: elections/templates/elections/election_voters.html:57
msgid "Supprimer" msgid "Supprimer"
msgstr "Delete" msgstr "Delete"
#: elections/forms.py:105 #: elections/forms.py:95
msgid "Non" msgid "Non"
msgstr "No" msgstr "No"
#: elections/forms.py:105 #: elections/forms.py:95
msgid "Oui" msgid "Oui"
msgstr "Yes" msgstr "Yes"
#: elections/models.py:31 #: elections/models.py:30
msgid "nom" msgid "nom"
msgstr "name" msgstr "name"
#: elections/models.py:32 #: elections/models.py:31
msgid "nom bref" msgid "nom bref"
msgstr "short name" msgstr "short name"
#: elections/models.py:34 #: elections/models.py:33
msgid "description" msgid "description"
msgstr "description" msgstr "description"
#: elections/models.py:37 #: elections/models.py:36
msgid "date et heure de début" msgid "date et heure de début"
msgstr "start date and time" msgstr "start date and time"
#: elections/models.py:38 #: elections/models.py:37
msgid "date et heure de fin" msgid "date et heure de fin"
msgstr "end date and time" msgstr "end date and time"
#: elections/models.py:41 #: elections/models.py:40
msgid "conditions de vote" msgid "conditions de vote"
msgstr "voting requirements" msgstr "voting requirements"
#: elections/models.py:45 #: elections/models.py:44
msgid "restreint le vote à une liste de personnes" msgid "restreint le vote à une liste de personnes"
msgstr "restricts the vote to a list of people" msgstr "restricts the vote to a list of people"
#: elections/models.py:49 #: elections/models.py:48
msgid "mail avec les identifiants envoyé" msgid "mail avec les identifiants envoyé"
msgstr "mail with credentials sent" msgstr "mail with credentials sent"
#: elections/models.py:66 #: elections/models.py:65
msgid "résultats publics" msgid "résultats publics"
msgstr "results published" msgstr "results published"
#: elections/models.py:67 #: elections/models.py:66
msgid "dépouillée" msgid "dépouillée"
msgstr "counted" msgstr "counted"
#: elections/models.py:69 #: elections/models.py:68
msgid "archivée" msgid "archivée"
msgstr "archived" msgstr "archived"
#: elections/models.py:79 #: elections/models.py:78
msgid "question" msgid "question"
msgstr "question" msgstr "question"
#: elections/models.py:81 #: elections/models.py:80
msgid "type de question" msgid "type de question"
msgstr "type of question" msgstr "type of question"
#: elections/models.py:88 #: elections/models.py:87
msgid "nombre maximal de votes reçus" msgid "nombre maximal de votes reçus"
msgstr "maximal number of votes received" msgstr "maximal number of votes received"
#: elections/models.py:135 #: elections/models.py:134
msgid "texte" msgid "texte"
msgstr "text" msgstr "text"
#: elections/models.py:137 #: elections/models.py:136
msgid "option gagnante" msgid "option gagnante"
msgstr "winning option" msgstr "winning option"
#: elections/models.py:145 #: elections/models.py:144
msgid "nombre de votes reçus" msgid "nombre de votes reçus"
msgstr "number of votes received" msgstr "number of votes received"
#: elections/models.py:164 #: elections/models.py:163
msgid "rang de l'option" msgid "rang de l'option"
msgstr "option's ranking" msgstr "option's ranking"
#: elections/models.py:180 #: elections/models.py:179
msgid "votes supplémentaires" msgid "votes supplémentaires"
msgstr "extra votes" msgstr "extra votes"
#: elections/models.py:196 #: elections/models.py:195
msgid "Nom et Prénom" msgid "Nom et Prénom"
msgstr "Name and surname" msgstr "Name and surname"
#: elections/models.py:218 elections/tests/test_models.py:57 #: elections/models.py:217 elections/tests/test_models.py:57
msgid "identifiants spécifiques" msgid "identifiants spécifiques"
msgstr "dedicated credentials" msgstr "dedicated credentials"
#: elections/models.py:222 #: elections/models.py:221
msgid "Peut administrer des élections" msgid "Peut administrer des élections"
msgstr "Can manage elections" msgstr "Can manage elections"
@ -285,49 +285,53 @@ msgstr "Login via CAS"
msgid "A voté" msgid "A voté"
msgstr "Voted" msgstr "Voted"
#: elections/templates/elections/election_admin.html:41 #: elections/templates/elections/election_admin.html:40
msgid "Actions" msgid "Actions"
msgstr "Actions" msgstr "Actions"
#: elections/templates/elections/election_admin.html:54 #: elections/templates/elections/election_admin.html:52
#: elections/templates/elections/election_admin.html:177 msgid "Exporter les votant·e·s"
#: elections/templates/elections/election_admin.html:200 msgstr "Export the list of voters"
#: elections/templates/elections/election_admin.html:61
#: elections/templates/elections/election_admin.html:183
#: elections/templates/elections/election_admin.html:206
msgid "Modifier" msgid "Modifier"
msgstr "Edit" msgstr "Edit"
#: elections/templates/elections/election_admin.html:63 #: elections/templates/elections/election_admin.html:70
#: elections/templates/elections/upload_voters.html:25 #: elections/templates/elections/upload_voters.html:25
msgid "Gestion de la liste de votant·e·s" msgid "Gestion de la liste de votant·e·s"
msgstr "Management of the voters' list" msgstr "Management of the voters' list"
#: elections/templates/elections/election_admin.html:75 #: elections/templates/elections/election_admin.html:82
#: elections/templates/elections/election_voters.html:27 #: elections/templates/elections/election_voters.html:27
msgid "Liste des votant·e·s" msgid "Liste des votant·e·s"
msgstr "Voters' list" msgstr "Voters' list"
#: elections/templates/elections/election_admin.html:83 #: elections/templates/elections/election_admin.html:90
msgid "Dépouiller" msgid "Dépouiller"
msgstr "Count" msgstr "Count"
#: elections/templates/elections/election_admin.html:94 #: elections/templates/elections/election_admin.html:101
msgid "Publier" msgid "Publier"
msgstr "Publish" msgstr "Publish"
#: elections/templates/elections/election_admin.html:96 #: elections/templates/elections/election_admin.html:103
msgid "Dépublier" msgid "Dépublier"
msgstr "De-publish" msgstr "De-publish"
#: elections/templates/elections/election_admin.html:106 #: elections/templates/elections/election_admin.html:113
msgid "Archiver" msgid "Archiver"
msgstr "Archive" msgstr "Archive"
#: elections/templates/elections/election_admin.html:243 #: elections/templates/elections/election_admin.html:249
#: elections/templates/elections/election_admin.html:254 #: elections/templates/elections/election_admin.html:260
msgid "Rajouter une option" msgid "Rajouter une option"
msgstr "Add an option" msgstr "Add an option"
#: elections/templates/elections/election_admin.html:258 #: elections/templates/elections/election_admin.html:264
#: elections/templates/elections/election_admin.html:268 #: elections/templates/elections/election_admin.html:274
msgid "Rajouter une question" msgid "Rajouter une question"
msgstr "Add a question" msgstr "Add a question"
@ -535,55 +539,55 @@ msgstr "Missing value in line {}: 'name'."
msgid "Adresse mail invalide à la ligne {} : '{}'." msgid "Adresse mail invalide à la ligne {} : '{}'."
msgstr "Invalid e-mail address in line {}: '{}'." msgstr "Invalid e-mail address in line {}: '{}'."
#: elections/views.py:69 #: elections/views.py:73
msgid "Élection créée avec succès !" msgid "Élection créée avec succès !"
msgstr "Election successfully created!" msgstr "Election successfully created!"
#: elections/views.py:113 #: elections/views.py:133
msgid "Liste de votant·e·s importée avec succès !" msgid "Liste de votant·e·s importée avec succès !"
msgstr "Voters list successfully imported!" msgstr "Voters list successfully imported!"
#: elections/views.py:147 #: elections/views.py:167
msgid "Mail d'annonce envoyé avec succès !" msgid "Mail d'annonce envoyé avec succès !"
msgstr "Announcement e-mail sent successfully!" msgstr "Announcement e-mail sent successfully!"
#: elections/views.py:179 #: elections/views.py:199
msgid "Élection modifiée avec succès !" msgid "Élection modifiée avec succès !"
msgstr "Election successfully modified!" msgstr "Election successfully modified!"
#: elections/views.py:249 #: elections/views.py:269
msgid "Élection dépouillée avec succès !" msgid "Élection dépouillée avec succès !"
msgstr "Election successfully counted!" msgstr "Election successfully counted!"
#: elections/views.py:275 #: elections/views.py:295
msgid "Élection publiée avec succès !" msgid "Élection publiée avec succès !"
msgstr "Election successfully published!" msgstr "Election successfully published!"
#: elections/views.py:276 #: elections/views.py:296
msgid "Élection dépubliée avec succès !" msgid "Élection dépubliée avec succès !"
msgstr "Election successfully de-published!" msgstr "Election successfully de-published!"
#: elections/views.py:288 #: elections/views.py:308
msgid "Élection archivée avec succès !" msgid "Élection archivée avec succès !"
msgstr "Election successfully archived!" msgstr "Election successfully archived!"
#: elections/views.py:320 #: elections/views.py:340
msgid "Question modifiée avec succès !" msgid "Question modifiée avec succès !"
msgstr "Question successfully modified!" msgstr "Question successfully modified!"
#: elections/views.py:332 #: elections/views.py:352
msgid "Question supprimée !" msgid "Question supprimée !"
msgstr "Question deleted!" msgstr "Question deleted!"
#: elections/views.py:370 #: elections/views.py:390
msgid "Option modifiée avec succès !" msgid "Option modifiée avec succès !"
msgstr "Option successfully modified!" msgstr "Option successfully modified!"
#: elections/views.py:382 #: elections/views.py:402
msgid "Option supprimée !" msgid "Option supprimée !"
msgstr "Option deleted!" msgstr "Option deleted!"
#: elections/views.py:522 #: elections/views.py:542
msgid "Votre choix a bien été enregistré !" msgid "Votre choix a bien été enregistré !"
msgstr "Your choice has been recorded!" msgstr "Your choice has been recorded!"