Begin sending mail in the background

This commit is contained in:
Tom Hubrecht 2021-06-19 21:06:22 +02:00
parent f4f5611eaf
commit 6d98f63f0b
7 changed files with 108 additions and 26 deletions

View file

@ -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é",
),
),
]

View file

@ -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):

View file

@ -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

View file

@ -29,7 +29,7 @@
</div>
<div class="level-right">
{% if not election.sent_mail %}
{% if election.sent_mail is False %}
<div class="level-item">
<a class="button is-light is-outlined is-primary" href="{% url 'election.mail-voters' election.pk %}">
<span class="icon">
@ -38,6 +38,15 @@
<span>{% trans "Envoyer le mail d'annonce" %}</span>
</a>
</div>
{% elif election.sent_mail is None %}
<div class="level-item">
<span class="button is-light is-outlined is-warning">
<span class="icon">
<i class="fas fa-sync-alt"></i>
</span>
<span>{% trans "Mail en cours de distribution" %}</span>
</span>
</div>
{% endif %}
<div class="level-item">
@ -50,10 +59,10 @@
</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 %}
{% if election.sent_mail is False %}
<hr>
<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>" %}
@ -114,7 +123,18 @@
<tr>
<td>{{ v.base_username }}</td>
<td>{{ v.full_name }}</td>
<td>{{ v.email }}</td>
<td>
{{ v.email }}
{% if v.has_valid_email %}
<span class="icon has-text-success is-pulled-right">
<i class="fas fa-check"></i>
</span>
{% elif v.has_valid_email is False %}
<span class="icon has-text-danger is-pulled-right">
<i class="fas fa-times"></i>
</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>

View file

@ -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"])

View file

@ -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)

View file

@ -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}")