Permet d'envoyer un mail à tous les votant·e·s avec leurs identifiants

This commit is contained in:
Tom Hubrecht 2020-12-24 00:41:29 +01:00
parent b44f150cf9
commit bab2629236
11 changed files with 202 additions and 14 deletions

View file

@ -42,6 +42,11 @@ class UploadVotersForm(forms.Form):
return csv_file
class VoterMailForm(forms.Form):
objet = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
class QuestionForm(forms.ModelForm):
class Meta:
model = Question

View file

@ -0,0 +1,20 @@
# Generated by Django 2.2.17 on 2020-12-23 19:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0005_user_full_name"),
]
operations = [
migrations.AddField(
model_name="election",
name="sent_mail",
field=models.BooleanField(
default=False, verbose_name="mail avec les identifiants envoyé"
),
),
]

View file

@ -20,6 +20,10 @@ class Election(models.Model):
_("restreint le vote à une liste de personnes"), default=True
)
sent_mail = models.BooleanField(
_("mail avec les identifiants envoyé"), default=False
)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name="elections_created",

12
elections/staticdefs.py Normal file
View file

@ -0,0 +1,12 @@
MAIL_VOTERS = (
"Dear {full_name},\n"
"\n"
"\n"
"Election URL: {election_url}\n"
"\n"
"Your voter ID: {username}\n"
"Your password: {password}\n"
"\n"
"-- \n"
"Kadenios"
)

View file

@ -40,7 +40,7 @@
<span class="icon">
<i class="fas fa-file-import"></i>
</span>
<span>{% trans "Importer une liste de votant·e·s" %}</span>
<span>{% trans "Gestion de la liste de votant·e·s" %}</span>
</a>
</div>
{% endif %}

View file

@ -0,0 +1,51 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h1 class="title">{% trans "Composition du mail aux votant·e·s" %}</h1>
<hr>
<div class="message is-warning">
<div class="message-body">
{% trans "Assurez-vous que la liste des votant·e·s est complète, en effet, une fois le mail envoyé, il ne sera plus possible de la modifier." %}
</div>
</div>
<div class="message is-primary">
<div class="message-body">
{% trans "Rajoutez le message à envoyer aux électeurs entre 'Dear {full_name}' et l'url de l'élection." %}
</div>
</div>
<div class="columns is-centered">
<div class="column is-two-thirds">
<form action="" method="post" enctype="multipart/form-data" id="import-voters">
{% csrf_token %}
{% include "forms/form.html" %}
<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 "Envoyer" %}</span>
</button>
</div>
<div class="control">
<a class="button is-primary" href="{% url 'election.upload-voters' 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

@ -19,9 +19,39 @@
{% block content %}
<h1 class="title">{% trans "Importer une liste de votant·e·s" %}</h1>
<div class="level">
<div class="level-left">
<div class="item-level">
<h1 class="title">{% trans "Gestion de la liste de votant·e·s" %}</h1>
</div>
</div>
<div class="level-right">
{% if not election.sent_mail %}
<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>
{% endif %}
<div class="level-item">
<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>
</div>
<hr>
{# Si on a déjà envoyé le mail avec les identifiants, on ne peut plus changer la liste #}
{% if not election.sent_mail %}
<div class="message is-warning">
<div class="message-body">
{% trans "Importez un fichier au format CSV, avec sur la première colonne le login, sur la deuxième, le nom et prénom et enfin l'adresse email sur la troisième. Soit :<br><br><pre>Login_1,Prénom/Nom_1,mail_1@machin.test<br>Login_2,Prénom/Nom_2,mail_2@bidule.test<br>...</pre>" %}
@ -50,23 +80,16 @@
<span class="icon is-small">
<i class="fas fa-check"></i>
</span>
<span>{% trans "Enregistrer" %}</span>
<span>{% trans "Importer" %}</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>
<br>
{% endif %}
{# Liste des votant·e·s #}
{% if voters %}

View file

@ -7,6 +7,11 @@ 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(
"mail-voters/<int:pk>",
views.ElectionMailVotersView.as_view(),
name="election.mail-voters",
),
path(
"upload-voters/<int:pk>",
views.ElectionUploadVotersView.as_view(),

View file

@ -1,10 +1,15 @@
import csv
import io
import random
from django.contrib.auth.hashers import make_password
from django.core.exceptions import ValidationError
from django.core.mail import EmailMessage, get_connection
from django.core.validators import validate_email
from django.utils.translation import gettext_lazy as _
from .models import User
def create_users(election, csv_file):
"""Crée les votant·e·s pour l'élection donnée, en remplissant les champs
@ -72,8 +77,37 @@ def check_csv(csv_file):
return errors
def send_mail(election):
def generate_password():
random.seed()
alphabet = "abcdefghjkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
password = ""
for i in range(15):
password += random.choice(alphabet)
return password
def send_mail(election, mail_form):
"""Envoie le mail d'annonce de l'élection avec identifiants et mot de passe
aux votant·e·s, le mdp est généré en même temps que le mail est envoyé.
"""
pass
voters = list(election.registered_voters.all())
url = f"https://kadenios.eleves.ens.fr/elections/view/{election.id}"
messages = []
for v in voters:
password = generate_password()
v.password = make_password(password)
messages.append(
EmailMessage(
subject=mail_form.cleaned_data["objet"],
body=mail_form.cleaned_data["message"].format(
full_name=v.full_name,
election_url=url,
username=v.base_username,
password=password,
),
to=[v.email],
)
)
get_connection(fail_silently=False).send_messages(messages)
User.objects.bulk_update(voters, ["password"])

View file

@ -22,10 +22,12 @@ from .forms import (
OptionFormSet,
QuestionForm,
UploadVotersForm,
VoterMailForm,
)
from .mixins import CreatorOnlyEditMixin, CreatorOnlyMixin, OpenElectionOnlyMixin
from .models import Election, Option, Question
from .utils import create_users
from .staticdefs import MAIL_VOTERS
from .utils import create_users, send_mail
# TODO: access control *everywhere*
@ -116,6 +118,33 @@ class ElectionUploadVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormVi
return super().form_valid(form)
class ElectionMailVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormView):
model = Election
form_class = VoterMailForm
success_message = _("Mail d'annonce envoyé avec succès !")
template_name = "elections/mail_voters.html"
def get_success_url(self):
return reverse("election.upload-voters", args=[self.object.pk])
def get_initial(self):
return {"objet": f"Vote : {self.object.name}", "message": MAIL_VOTERS}
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
def form_valid(self, form):
self.object.sent_mail = True
send_mail(self.object, form)
self.object.save()
return super().form_valid(form)
class ElectionListView(CreatorOnlyMixin, ListView):
model = Election
template_name = "elections/election_list.html"

View file

@ -109,6 +109,11 @@ USE_L10N = True
USE_TZ = True
# Mail configuration
DEFAULT_FROM_EMAIL = "Kadenios <klub-dev@ens.fr>"
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/