diff --git a/elections/migrations/0030_auto_20210619_1845.py b/elections/migrations/0030_auto_20210619_1845.py new file mode 100644 index 0000000..1470675 --- /dev/null +++ b/elections/migrations/0030_auto_20210619_1845.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.4 on 2021-06-19 16:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("elections", "0029_alter_election_visible"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="has_valid_email", + field=models.BooleanField( + default=None, null=True, verbose_name="email valide" + ), + ), + migrations.AlterField( + model_name="election", + name="sent_mail", + field=models.BooleanField( + default=False, + null=True, + verbose_name="mail avec les identifiants envoyé", + ), + ), + ] diff --git a/elections/models.py b/elections/models.py index cdc02e2..7fed2d2 100644 --- a/elections/models.py +++ b/elections/models.py @@ -50,7 +50,7 @@ class Election(models.Model): ) sent_mail = models.BooleanField( - _("mail avec les identifiants envoyé"), default=False + _("mail avec les identifiants envoyé"), null=True, default=False ) created_by = models.ForeignKey( @@ -222,6 +222,7 @@ class User(AbstractUser): on_delete=models.CASCADE, ) full_name = models.CharField(_("Nom et Prénom"), max_length=150, blank=True) + has_valid_email = models.BooleanField(_("email valide"), null=True, default=None) @property def base_username(self): diff --git a/elections/tasks.py b/elections/tasks.py index fe7a859..0401872 100644 --- a/elections/tasks.py +++ b/elections/tasks.py @@ -1,2 +1,13 @@ -def send_election_mail(election): - pass +from celery import shared_task + +from .models import Election +from .utils import send_mail + + +@shared_task +def send_election_mail(election_pk, subject, body): + election = Election.objects.get(pk=election_pk) + send_mail(election, subject, body) + election.sent_mail = False + election.save() + # election.sent_mail = True diff --git a/elections/templates/elections/upload_voters.html b/elections/templates/elections/upload_voters.html index a657596..fb8baab 100644 --- a/elections/templates/elections/upload_voters.html +++ b/elections/templates/elections/upload_voters.html @@ -29,7 +29,7 @@
- {% if not election.sent_mail %} + {% if election.sent_mail is False %}
@@ -38,6 +38,15 @@ {% trans "Envoyer le mail d'annonce" %}
+ {% elif election.sent_mail is None %} +
+ + + + + {% trans "Mail en cours de distribution" %} + +
{% endif %}
@@ -50,10 +59,10 @@
-
{# Si on a déjà envoyé le mail avec les identifiants, on ne peut plus changer la liste #} -{% if not election.sent_mail %} +{% if election.sent_mail is False %} +
{% 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 :

Login_1,Prénom/Nom_1,mail_1@machin.test
Login_2,Prénom/Nom_2,mail_2@bidule.test
...
" %} @@ -114,7 +123,18 @@ {{ v.base_username }} {{ v.full_name }} - {{ v.email }} + + {{ v.email }} + {% if v.has_valid_email %} + + + + {% elif v.has_valid_email is False %} + + + + {% endif %} + {% endfor %} diff --git a/elections/utils.py b/elections/utils.py index 90633e2..aa3cac3 100644 --- a/elections/utils.py +++ b/elections/utils.py @@ -1,5 +1,6 @@ import csv import io +import smtplib import networkx as nx import numpy as np @@ -8,7 +9,7 @@ from networkx.algorithms.dag import ancestors, descendants from django.contrib.auth import get_user_model 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.mail import EmailMessage from django.core.validators import validate_email from django.template.loader import render_to_string from django.urls import reverse @@ -378,13 +379,14 @@ def check_csv(csv_file): return errors -def send_mail(election, mail_form): +def send_mail(election, subject, body): """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é. """ User = get_user_model() - voters = list(election.registered_voters.all()) + # On n'envoie le mail qu'aux personnes qui n'en n'ont pas déjà reçu un + voters = list(election.registered_voters.exclude(has_valid_email=True)) e_url = reverse("election.view", args=[election.id]) url = f"https://vote.eleves.ens.fr{e_url}" messages = [] @@ -392,18 +394,27 @@ def send_mail(election, mail_form): 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, + ( + EmailMessage( + subject=subject, + body=body.format( + full_name=v.full_name, + election_url=url, + username=v.base_username, + password=password, + ), + to=[v.email], ), - to=[v.email], + v, ) ) # get_connection(fail_silently=False).send_messages(messages) - for m in messages: - m.send() - User.objects.bulk_update(voters, ["password"]) + for (m, v) in messages: + try: + m.send() + except smtplib.SMTPException: + v.has_valid_email = False + else: + v.has_valid_email = True + + User.objects.bulk_update(voters, ["password", "has_valid_email"]) diff --git a/elections/views.py b/elections/views.py index ea8704a..d2b89a6 100644 --- a/elections/views.py +++ b/elections/views.py @@ -41,7 +41,8 @@ from .mixins import ( ) from .models import Election, Option, Question, Vote from .staticdefs import MAIL_VOTE_DELETED, MAIL_VOTERS, QUESTION_TYPES, VOTE_RULES -from .utils import create_users, send_mail +from .tasks import send_election_mail +from .utils import create_users User = get_user_model() @@ -158,7 +159,7 @@ class ElectionUploadVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormVi class ElectionMailVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormView): model = Election form_class = VoterMailForm - success_message = _("Mail d'annonce envoyé avec succès !") + success_message = _("Mail d'annonce en cours d'envoi !") template_name = "elections/mail_voters.html" def get_queryset(self): @@ -181,9 +182,16 @@ class ElectionMailVotersView(CreatorOnlyEditMixin, SuccessMessageMixin, FormView return super().post(request, *args, **kwargs) def form_valid(self, form): - self.object.sent_mail = True - send_mail(self.object, form) + self.object.sent_mail = None self.object.save() + send_election_mail.apply_async( + countdown=5, + kwargs={ + "election_pk": self.object.pk, + "subject": form.cleaned_data["objet"], + "body": form.cleaned_data["message"], + }, + ) return super().form_valid(form) diff --git a/kadenios/celery.py b/kadenios/celery.py index 0cefb00..19645dd 100644 --- a/kadenios/celery.py +++ b/kadenios/celery.py @@ -12,4 +12,6 @@ app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): - print(f"Request: {self.request!r}") + print(f"{'test'!r}") + return 3 + # print(f"Request: {self.request!r}")