From fe8f18ff78db31085f7264d6b10377241b26ad0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 22 Dec 2016 02:00:10 +0100 Subject: [PATCH 01/13] Utilise django_custommail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - On installe le package depuis le dépôt COF-Geek - On supprime tous les fichiers texte des mails - On charge dans la bdd les mails nécessaires au fonctionnement de GestioCOF - On supprime le modèle CustomMail obsolète de gestioncof --- bda/models.py | 179 ++++++++---------- bda/templates/bda/mails/buy-shotgun.txt | 6 - bda/templates/bda/mails/rappel.txt | 23 --- bda/templates/bda/mails/revente-loser.txt | 9 - bda/templates/bda/mails/revente-new.txt | 13 -- bda/templates/bda/mails/revente-seller.txt | 7 - bda/templates/bda/mails/revente-winner.txt | 7 - bda/templates/bda/mails/revente.txt | 12 -- bda/templates/bda/mails/shotgun.txt | 11 -- bda/views.py | 65 +++---- cof/settings_dev.py | 1 + gestioncof/admin.py | 7 +- gestioncof/models.py | 16 -- gestioncof/petits_cours_views.py | 26 +-- gestioncof/shared.py | 17 +- .../templates/petits-cours-mail-demandeur.txt | 17 -- .../templates/petits-cours-mail-eleve.txt | 28 --- gestioncof/views.py | 16 +- requirements.txt | 3 +- 19 files changed, 147 insertions(+), 316 deletions(-) delete mode 100644 bda/templates/bda/mails/buy-shotgun.txt delete mode 100644 bda/templates/bda/mails/rappel.txt delete mode 100644 bda/templates/bda/mails/revente-loser.txt delete mode 100644 bda/templates/bda/mails/revente-new.txt delete mode 100644 bda/templates/bda/mails/revente-seller.txt delete mode 100644 bda/templates/bda/mails/revente-winner.txt delete mode 100644 bda/templates/bda/mails/revente.txt delete mode 100644 bda/templates/bda/mails/shotgun.txt delete mode 100644 gestioncof/templates/petits-cours-mail-demandeur.txt delete mode 100644 gestioncof/templates/petits-cours-mail-eleve.txt diff --git a/bda/models.py b/bda/models.py index 85c7fa4d..b2dc1145 100644 --- a/bda/models.py +++ b/bda/models.py @@ -7,12 +7,11 @@ from __future__ import unicode_literals import calendar import random from datetime import timedelta +from custommail.utils import send_custom_mail, send_mass_custom_mail from django.contrib.sites.models import Site from django.db import models from django.contrib.auth.models import User -from django.template import loader -from django.core import mail from django.conf import settings from django.utils import timezone, formats from django.utils.encoding import python_2_unicode_compatible @@ -100,27 +99,24 @@ class Spectacle(models.Model): if member.id in members: members[member.id][1] = 2 else: - members[member.id] = [member.first_name, 1, member.email] - # Pour le BdA - members[0] = ['BdA', 1, 'bda@ens.fr'] - members[-1] = ['BdA', 2, 'bda@ens.fr'] + members[member.id] = [member, 1] + # FIXME : faire quelque chose de ça, un utilisateur bda_generic ? + # # Pour le BdA + # members[0] = ['BdA', 1, 'bda@ens.fr'] + # members[-1] = ['BdA', 2, 'bda@ens.fr'] # On écrit un mail personnalisé à chaque participant - mails_to_send = [] - mail_object = str(self) - for member in members.values(): - mail_body = loader.render_to_string('bda/mails/rappel.txt', { - 'name': member[0], - 'nb_attr': member[1], - 'show': self}) - mail_tot = mail.EmailMessage( - mail_object, mail_body, - settings.MAIL_DATA['rappels']['FROM'], [member[2]], - [], headers={ - 'Reply-To': settings.MAIL_DATA['rappels']['REPLYTO']}) - mails_to_send.append(mail_tot) - # On envoie les mails - connection = mail.get_connection() - connection.send_messages(mails_to_send) + mails_data = [ + ( + member[0].email, + {'member': member[0],'nb_attr': member[1], 'show': self} + ) + for member in members.values() + ] + send_mass_custom_mail( + 'bda-rappel', + mails_data, + from_email=settings.MAIL_DATA['rappels']['FROM'] + ) # On enregistre le fait que l'envoi a bien eu lieu self.rappel_sent = timezone.now() self.save() @@ -263,26 +259,28 @@ class SpectacleRevente(models.Model): verbose_name = "Revente" def send_notif(self): + """ + Envoie une notification pour indiquer la mise en vente d'une place sur + BdA-Revente à tous les intéressés. + """ inscrits = self.attribution.spectacle.subscribed.select_related('user') - - mails_to_send = [] - mail_object = "%s" % (self.attribution.spectacle) - for participant in inscrits: - mail_body = loader.render_to_string('bda/mails/revente.txt', { - 'user': participant.user, - 'spectacle': self.attribution.spectacle, - 'revente': self, - 'domain': Site.objects.get_current().domain}) - mail_tot = mail.EmailMessage( - mail_object, mail_body, - settings.MAIL_DATA['revente']['FROM'], - [participant.user.email], - [], headers={ - 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) - mails_to_send.append(mail_tot) - - connection = mail.get_connection() - connection.send_messages(mails_to_send) + mails_data = [ + ( + participant.user.email, + { + 'member': participant.user, + 'show': self.attribution.spectacle, + 'revente': self, + 'site': Site.objects.get_current() + } + ) + for participant in inscrits + ] + send_mass_custom_mail( + "bda-revente", + mails_data, + from_email=settings.MAIL_DATA['revente']['FROM'], + ) self.notif_sent = True self.save() @@ -292,25 +290,22 @@ class SpectacleRevente(models.Model): leur indiquer qu'il est désormais disponible au shotgun. """ inscrits = self.attribution.spectacle.subscribed.select_related('user') - - mails_to_send = [] - mail_object = "%s" % (self.attribution.spectacle) - for participant in inscrits: - mail_body = loader.render_to_string('bda/mails/shotgun.txt', { - 'user': participant.user, - 'spectacle': self.attribution.spectacle, - 'domain': Site.objects.get_current(), - 'mail': self.attribution.participant.user.email}) - mail_tot = mail.EmailMessage( - mail_object, mail_body, - settings.MAIL_DATA['revente']['FROM'], - [participant.user.email], - [], headers={ - 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) - mails_to_send.append(mail_tot) - - connection = mail.get_connection() - connection.send_messages(mails_to_send) + mails_data = [ + ( + participant.user.email, + { + 'member': participant.user, + 'show': self.attribution.spectacle, + 'site': Site.objects.get_current(), + } + ) + for participant in inscrits + ] + send_mass_custom_mail( + "bda-shotgun", + mails_data, + from_email=settings.MAIL_DATA['revente']['FROM'] + ) self.notif_sent = True self.save() @@ -325,51 +320,43 @@ class SpectacleRevente(models.Model): seller = self.seller if inscrits: - mails = [] - mail_subject = "BdA-Revente : {:s}".format(spectacle.title) - # Envoie un mail au gagnant et au vendeur winner = random.choice(inscrits) self.soldTo = winner context = { 'acheteur': winner.user, 'vendeur': seller.user, - 'spectacle': spectacle, + 'show': spectacle, } - mails.append(mail.EmailMessage( - mail_subject, - loader.render_to_string('bda/mails/revente-winner.txt', - context), - from_email=settings.MAIL_DATA['revente']['FROM'], - to=[winner.user.email], - reply_to=[seller.user.email], - )) - mails.append(mail.EmailMessage( - mail_subject, - loader.render_to_string('bda/mails/revente-seller.txt', - context), - from_email=settings.MAIL_DATA['revente']['FROM'], - to=[seller.user.email], - reply_to=[winner.user.email], - )) + send_custom_mail( + winner.user.email, + 'bda-revente-winner', + context=context, + from_email=settings.MAIL_DATA['revente']['FROM'] + ) + send_custom_mail( + seller.user.email, + 'bda-revente-seller', + context=context, + from_email=settings.MAIL_DATA['revente']['FROM'] + ) # Envoie un mail aux perdants - for inscrit in inscrits: - if inscrit == winner: - continue - - mail_body = loader.render_to_string( - 'bda/mails/revente-loser.txt', - {'acheteur': inscrit.user, - 'vendeur': seller.user, - 'spectacle': spectacle} + mails_data = [ + ( + inscrit.user.email, + { + 'acheteur': inscrit.user, + 'vendeur': seller.user, + 'show': spectacle + } ) - mails.append(mail.EmailMessage( - mail_subject, mail_body, - from_email=settings.MAIL_DATA['revente']['FROM'], - to=[inscrit.user.email], - reply_to=[settings.MAIL_DATA['revente']['REPLYTO']], - )) - mail.get_connection().send_messages(mails) + for inscrit in inscrits if inscrit == winner + ] + send_mass_custom_mail( + 'bda-revente-loser', + mails_data, + from_email=settings.MAIL_DATA['revente']['FROM'] + ) self.tirage_done = True self.save() diff --git a/bda/templates/bda/mails/buy-shotgun.txt b/bda/templates/bda/mails/buy-shotgun.txt deleted file mode 100644 index d7855143..00000000 --- a/bda/templates/bda/mails/buy-shotgun.txt +++ /dev/null @@ -1,6 +0,0 @@ -Bonjour {{ vendeur.first_name }} ! - -Je souhaiterais racheter ta place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. -Contacte-moi si tu es toujours intéressé·e ! - -{{ acheteur.get_full_name }} ({{ acheteur.email }}) diff --git a/bda/templates/bda/mails/rappel.txt b/bda/templates/bda/mails/rappel.txt deleted file mode 100644 index c6433f8a..00000000 --- a/bda/templates/bda/mails/rappel.txt +++ /dev/null @@ -1,23 +0,0 @@ -Bonjour {{ name }}, - -Nous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:"une place,deux places" }} -pour {{ show.title }}, le {{ show.date }} au {{ show.location }}. N'oublie pas de t'y rendre ! -{% if nb_attr == 2 %} -Tu as obtenu deux places pour ce spectacle. Nous te rappelons que -ces places sont strictement réservées aux personnes de moins de 28 ans. -{% endif %} -{% if show.listing %}Pour ce spectacle, tu as reçu des places sur -listing. Il te faudra donc te rendre 15 minutes en avance sur les lieux de la représentation -pour retirer {{ nb_attr|pluralize:"ta place,tes places" }}. -{% else %}Pour assister à ce spectacle, tu dois présenter les billets qui ont -été distribués au burô. -{% endif %} - -Si tu ne peux plus assister à cette représentation, tu peux -revendre ta place via BdA-revente, accessible directement sur -GestioCOF (lien "revendre une place du premier tirage" sur la page -d'accueil https://www.cof.ens.fr/gestion/). - -En te souhaitant un excellent spectacle, - -Le Bureau des Arts diff --git a/bda/templates/bda/mails/revente-loser.txt b/bda/templates/bda/mails/revente-loser.txt deleted file mode 100644 index 6b50944d..00000000 --- a/bda/templates/bda/mails/revente-loser.txt +++ /dev/null @@ -1,9 +0,0 @@ -Bonjour {{ acheteur.first_name }}, - -Tu t'étais inscrit-e pour la revente de la place de {{ vendeur.get_full_name }} -pour {{ spectacle.title }}. -Malheureusement, une autre personne a été tirée au sort pour racheter la place. -Tu pourras certainement retenter ta chance pour une autre revente ! - -À très bientôt, -Le Bureau des Arts diff --git a/bda/templates/bda/mails/revente-new.txt b/bda/templates/bda/mails/revente-new.txt deleted file mode 100644 index ffba3083..00000000 --- a/bda/templates/bda/mails/revente-new.txt +++ /dev/null @@ -1,13 +0,0 @@ -Bonjour {{ vendeur.first_name }}, - -Tu t’es bien inscrit-e pour la revente de {{ spectacle.title }}. - -{% with revente.expiration_time as time %} -Le tirage au sort entre tout-e-s les racheteuse-eur-s potentiel-le-s aura lieu -le {{ time|date:"DATE_FORMAT" }} à {{ time|time:"TIME_FORMAT" }} (dans {{time|timeuntil }}). -Si personne ne s’est inscrit pour racheter la place, celle-ci apparaitra parmi -les « Places disponibles immédiatement à la revente » sur GestioCOF. -{% endwith %} - -Bonne revente ! -Le Bureau des Arts diff --git a/bda/templates/bda/mails/revente-seller.txt b/bda/templates/bda/mails/revente-seller.txt deleted file mode 100644 index ec99b98b..00000000 --- a/bda/templates/bda/mails/revente-seller.txt +++ /dev/null @@ -1,7 +0,0 @@ -Bonjour {{ vendeur.first_name }}, - -La personne tirée au sort pour racheter ta place pour {{ spectacle.title }} est {{ acheteur.get_full_name }}. -Tu peux le/la contacter à l'adresse {{ acheteur.email }}, ou en répondant à ce mail. - -Chaleureusement, -Le BdA diff --git a/bda/templates/bda/mails/revente-winner.txt b/bda/templates/bda/mails/revente-winner.txt deleted file mode 100644 index 01ecfb86..00000000 --- a/bda/templates/bda/mails/revente-winner.txt +++ /dev/null @@ -1,7 +0,0 @@ -Bonjour {{ acheteur.first_name }}, - -Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. -Tu peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail. - -Chaleureusement, -Le BdA diff --git a/bda/templates/bda/mails/revente.txt b/bda/templates/bda/mails/revente.txt deleted file mode 100644 index 397a58d8..00000000 --- a/bda/templates/bda/mails/revente.txt +++ /dev/null @@ -1,12 +0,0 @@ -Bonjour {{ user.first_name }} - -Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }}) -a été postée sur BdA-Revente. - -Si ce spectacle t'intéresse toujours, merci de nous le signaler en cliquant -sur ce lien : http://{{ domain }}{% url "bda-revente-interested" revente.id %}. -Dans le cas où plusieurs personnes seraient intéressées, nous procèderons à -un tirage au sort le {{ revente.expiration_time_str }}. - -Chaleureusement, -Le BdA diff --git a/bda/templates/bda/mails/shotgun.txt b/bda/templates/bda/mails/shotgun.txt deleted file mode 100644 index 69bc704c..00000000 --- a/bda/templates/bda/mails/shotgun.txt +++ /dev/null @@ -1,11 +0,0 @@ -Bonjour {{ user.first_name }} - -Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }}) -a été postée sur BdA-Revente. - -Puisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour -cette place : elle est disponible immédiatement à l'adresse -http://{{ domain }}{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous. - -Chaleureusement, -Le BdA diff --git a/bda/views.py b/bda/views.py index 72fd5dd2..a0767c67 100644 --- a/bda/views.py +++ b/bda/views.py @@ -5,19 +5,19 @@ from __future__ import print_function from __future__ import unicode_literals import random +from custommail.utils import send_mass_custom_mail, send_custom_mail from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required from django.db import models, transaction from django.db.models import Count, Q -from django.core import serializers, mail +from django.core import serializers from django.forms.models import inlineformset_factory from django.http import HttpResponseBadRequest, HttpResponseRedirect from django.core.urlresolvers import reverse from django.conf import settings import hashlib -from django.core.mail import send_mail from django.template import loader from django.utils import timezone from django.views.generic.list import ListView @@ -275,7 +275,7 @@ def revente(request, tirage_id): resellform = ResellForm(participant, request.POST, prefix='resell') annulform = AnnulForm(participant, prefix='annul') if resellform.is_valid(): - mails = [] + mails_data = [] attributions = resellform.cleaned_data["attributions"] with transaction.atomic(): for attribution in attributions: @@ -285,20 +285,18 @@ def revente(request, tirage_id): if not created: revente.seller = participant revente.date = timezone.now() - mail_subject = "BdA-Revente : {:s}".format(attribution.spectacle.title) - mail_body = loader.render_to_string('bda/mails/revente-new.txt', { + context = { 'vendeur': participant.user, - 'spectacle': attribution.spectacle, - 'revente': revente, - }) - mails.append(mail.EmailMessage( - mail_subject, mail_body, - from_email=settings.MAIL_DATA['revente']['FROM'], - to=[participant.user.email], - reply_to=[settings.MAIL_DATA['revente']['REPLYTO']], - )) + 'show': attribution.spectacle, + 'revente': revente + } + mails_data.append(participant.user.email, context) revente.save() - mail.get_connection().send_messages(mails) + send_mass_custom_mail( + 'bda-revente-new', + mails_data, + from_email=settings.MAIL_DATA['revente']['FROM'] + ) elif 'annul' in request.POST: annulform = AnnulForm(participant, request.POST, prefix='annul') @@ -453,15 +451,17 @@ def buy_revente(request, spectacle_id): revente = random.choice(reventes_shotgun) revente.soldTo = participant revente.save() - mail = loader.render_to_string('bda/mails/buy-shotgun.txt', { - 'spectacle': spectacle, + context = { + 'show': spectacle, 'acheteur': request.user, - 'vendeur': revente.seller.user, - }) - send_mail("BdA-Revente : %s" % spectacle.title, mail, - request.user.email, - [revente.seller.user.email], - fail_silently=False) + 'vendeur': revente.seller.user + } + send_custom_mail( + revente.seller.user.email, + 'bda-buy-shotgun', + context=context, + from_email='bda@ens.fr' + ) return render(request, "bda-success.html", {"seller": revente.attribution.participant.user, "spectacle": spectacle}) @@ -548,15 +548,16 @@ def unpaid(request, tirage_id): def send_rappel(request, spectacle_id): show = get_object_or_404(Spectacle, id=spectacle_id) # Mails d'exemples - fake_member = request.user - fake_member.nb_attr = 1 - exemple_mail_1place = loader.render_to_string('bda/mails/rappel.txt', { - 'member': fake_member, - 'show': show}) - fake_member.nb_attr = 2 - exemple_mail_2places = loader.render_to_string('bda/mails/rappel.txt', { - 'member': fake_member, - 'show': show}) + exemple_mail_1place = render_mail('bda-rappel', { + 'member': request.user, + 'show': show, + 'nb_attr': 1 + }) + exemple_mail_2place = render_mail('bda-rappel', { + 'member': request.user, + 'show': show, + 'nb_attr': 2 + }) # Contexte ctxt = {'show': show, 'exemple_mail_1place': exemple_mail_1place, diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 610ae549..50027803 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -50,6 +50,7 @@ INSTALLED_APPS = ( 'kfet', 'channels', 'widget_tweaks', + 'custommail', ) MIDDLEWARE_CLASSES = ( diff --git a/gestioncof/admin.py b/gestioncof/admin.py index eb8ad6c0..a177c26c 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -8,7 +8,7 @@ from django import forms from django.contrib import admin from django.utils.translation import ugettext_lazy as _ from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \ - CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \ + CofProfile, EventOption, EventOptionChoice, Event, Club, \ Survey, EventCommentField, EventRegistration from gestioncof.petits_cours_models import PetitCoursDemande, \ PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \ @@ -267,10 +267,6 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin): search_fields = ('name', 'email', 'phone', 'lieu', 'remarques') -class CustomMailAdmin(admin.ModelAdmin): - search_fields = ('shortname', 'title') - - class ClubAdminForm(forms.ModelForm): def clean(self): cleaned_data = super(ClubAdminForm, self).clean() @@ -297,7 +293,6 @@ admin.site.unregister(User) admin.site.register(User, UserProfileAdmin) admin.site.register(CofProfile) admin.site.register(Club, ClubAdmin) -admin.site.register(CustomMail) admin.site.register(PetitCoursSubject) admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin) admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin) diff --git a/gestioncof/models.py b/gestioncof/models.py index 19590aff..bafb9518 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -96,22 +96,6 @@ class Club(models.Model): return self.name -@python_2_unicode_compatible -class CustomMail(models.Model): - shortname = models.SlugField(max_length=50, blank=False) - title = models.CharField("Titre", max_length=200, blank=False) - content = models.TextField("Contenu", blank=False) - comments = models.TextField("Informations contextuelles sur le mail", - blank=True) - - class Meta: - verbose_name = "Mail personnalisable" - verbose_name_plural = "Mails personnalisables" - - def __str__(self): - return "%s: %s" % (self.shortname, self.title) - - @python_2_unicode_compatible class Event(models.Model): title = models.CharField("Titre", max_length=200) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 303cec2c..9474a087 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -4,9 +4,9 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +from custommail.utils import send_custom_mail, render_mail + from django.shortcuts import render, get_object_or_404, redirect -from django.core import mail -from django.core.mail import EmailMessage from django.forms import ModelForm from django import forms from django.forms.models import inlineformset_factory, BaseInlineFormSet @@ -131,7 +131,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for, proposed_for = proposed_for.items() attribdata = list(attribdata.items()) proposed_mails = _generate_eleve_email(demande, proposed_for) - mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", { + mainmail = render_mail("petits-cours-mail-demandeur", { "proposals": proposals, "unsatisfied": unsatisfied, "extra": @@ -155,14 +155,16 @@ def _finalize_traitement(request, demande, proposals, proposed_for, def _generate_eleve_email(demande, proposed_for): - proposed_mails = [] - for user, matieres in proposed_for: - msg = loader.render_to_string("petits-cours-mail-eleve.txt", { - "demande": demande, - "matieres": matieres - }) - proposed_mails.append((user, msg)) - return proposed_mails + return [ + ( + user, + render_mail('petit-cours-mail-eleve', { + "demande": demande, + "matieres": matieres + })[1] + ) + for user, matieres in proposed_for + ] def _traitement_other_preparing(request, demande): @@ -274,7 +276,7 @@ def _traitement_post(request, demande): proposals_list = proposals.items() proposed_for = proposed_for.items() proposed_mails = _generate_eleve_email(demande, proposed_for) - mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", { + mainmail = render_mail("petits-cours-mail-demandeur", { "proposals": proposals_list, "unsatisfied": unsatisfied, "extra": extra, diff --git a/gestioncof/shared.py b/gestioncof/shared.py index 8fe17d43..988b93ee 100644 --- a/gestioncof/shared.py +++ b/gestioncof/shared.py @@ -14,7 +14,7 @@ from django.db import connection from django.core.mail import send_mail from django.template import Template, Context -from gestioncof.models import CofProfile, CustomMail +from gestioncof.models import CofProfile User = get_user_model() @@ -99,18 +99,3 @@ def unlock_tables(*models): return row unlock_table = unlock_tables - - -def send_custom_mail(to, shortname, context=None, from_email="cof@ens.fr"): - if context is None: - context = {} - if isinstance(to, DjangoUser): - context["nom"] = to.get_full_name() - context["prenom"] = to.first_name - to = to.email - mail = CustomMail.objects.get(shortname=shortname) - template = Template(mail.content) - message = template.render(Context(context)) - send_mail(mail.title, message, - from_email, [to], - fail_silently=True) diff --git a/gestioncof/templates/petits-cours-mail-demandeur.txt b/gestioncof/templates/petits-cours-mail-demandeur.txt deleted file mode 100644 index 8c20834e..00000000 --- a/gestioncof/templates/petits-cours-mail-demandeur.txt +++ /dev/null @@ -1,17 +0,0 @@ -Bonjour, - -Je vous contacte au sujet de votre annonce passée sur le site du COF pour rentrer en contact avec un élève normalien pour des cours particuliers. Voici les coordonnées d'élèves qui sont motivés par de tels cours et correspondent aux critères que vous nous aviez transmis : - -{% for matiere, proposed in proposals %}¤ {{ matiere }} :{% for user in proposed %} - ¤ {{ user.get_full_name }}{% if user.profile.phone %}, {{ user.profile.phone }}{% endif %}{% if user.email %}, {{ user.email }}{% endif %}{% endfor %} - -{% endfor %}{% if unsatisfied %}Nous n'avons cependant pas pu trouver d'élève disponible pour des cours de {% for matiere in unsatisfied %}{% if forloop.counter0 > 0 %}, {% endif %}{{ matiere }}{% endfor %}. - -{% endif %}Si pour une raison ou une autre ces numéros ne suffisaient pas, n'hésitez pas à répondre à cet e-mail et je vous en ferai parvenir d'autres sans problème. -{% if extra|length > 0 %} -{{ extra|safe }} -{% endif %} -Cordialement, - --- -Le COF, BdE de l'ENS diff --git a/gestioncof/templates/petits-cours-mail-eleve.txt b/gestioncof/templates/petits-cours-mail-eleve.txt deleted file mode 100644 index f75fb33f..00000000 --- a/gestioncof/templates/petits-cours-mail-eleve.txt +++ /dev/null @@ -1,28 +0,0 @@ -Salut, - -Le COF a reçu une demande de petit cours qui te correspond. Tu es en haut de la liste d'attente donc on a transmis tes coordonnées, ainsi que celles de 2 autres qui correspondaient aussi (c'est la vie, on donne les numéros 3 par 3 pour que ce soit plus souple). Voici quelques infos sur l'annonce en question : - -¤ Nom : {{ demande.name }} - -¤ Période : {{ demande.quand }} - -¤ Fréquence : {{ demande.freq }} - -¤ Lieu (si préféré) : {{ demande.lieu }} - -¤ Niveau : {{ demande.get_niveau_display }} - -¤ Remarques diverses (désolé pour les balises HTML) : {{ demande.remarques }} - -{% if matieres|length > 1 %}¤ Matières : -{% for matiere in matieres %} ¤ {{ matiere }} -{% endfor %}{% else %}¤ Matière : {% for matiere in matieres %}{{ matiere }} -{% endfor %}{% endif %} -Voilà, cette personne te contactera peut-être sous peu, tu pourras voir les détails directement avec elle (prix, modalités, ...). Pour indication, 30 Euro/h semble être la moyenne. - -Si tu te rends compte qu'en fait tu ne peux pas/plus donner de cours en ce moment, ça serait cool que tu décoches la case "Recevoir des propositions de petits cours" sur GestioCOF. Ensuite dès que tu voudras réapparaître tu pourras recocher la case et tu seras à nouveau sur la liste. - -À bientôt, - --- -Le COF, pour les petits cours diff --git a/gestioncof/views.py b/gestioncof/views.py index 3bc8c2f9..e086b06c 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -8,6 +8,7 @@ import unicodecsv import uuid from datetime import timedelta from icalendar import Calendar, Event as Vevent +from custommail.utils import send_custom_mail from django.shortcuts import redirect, get_object_or_404, render from django.http import Http404, HttpResponse, HttpResponseForbidden @@ -24,7 +25,6 @@ from gestioncof.models import Event, EventRegistration, EventOption, \ EventOptionChoice from gestioncof.models import EventCommentField, EventCommentValue, \ CalendarSubscription -from gestioncof.shared import send_custom_mail from gestioncof.models import CofProfile, Clipper, Club from gestioncof.decorators import buro_required, cof_required from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \ @@ -438,7 +438,11 @@ def registration(request): # Enregistrement du profil profile = profile_form.save() if profile.is_cof and not was_cof: - send_custom_mail(member, "bienvenue") + send_custom_mail( + member.email, "welcome", + context={'member': member}, + from_email='cof@ens.fr' + ) # Enregistrement des inscriptions aux événements for form in event_formset: if 'status' not in form.cleaned_data: @@ -470,8 +474,12 @@ def registration(request): registration=current_registration).content except EventCommentValue.DoesNotExist: comments = field.default - send_custom_mail(member, "mega", - {"remarques": comments}) + # FIXME : il faut faire quelque chose de propre ici, + # par exemple écrire un mail générique pour + # l'inscription aux événements et/ou donner la + # possibilité d'associer un mail aux événements + # send_custom_mail(member, "mega", + # {"remarques": comments}) # Enregistrement des inscriptions aux clubs member.clubs.clear() for club in clubs_form.cleaned_data['clubs']: diff --git a/requirements.txt b/requirements.txt index f7f6deca..d0d53283 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,8 @@ django-bootstrap-form==3.2.1 asgiref==0.14.0 daphne==0.14.3 asgi-redis==0.14.0 -git+https://github.com/Aureplop/channels.git#egg=channel statistics==1.0.3.5 future==0.15.2 django-widget-tweaks==1.4.1 +git+https://github.com/Aureplop/channels.git#egg=channel +git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_custommail From 5f29caec3c5906cb35960fa6cb4838ed04434152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 22 Dec 2016 12:28:03 +0100 Subject: [PATCH 02/13] cleanup --- bda/forms.py | 1 - bda/models.py | 6 +-- bda/views.py | 67 ++++++++++++++++---------------- gestioncof/petits_cours_views.py | 33 +++++++--------- gestioncof/shared.py | 9 ++--- gestioncof/views.py | 30 +++++++------- 6 files changed, 67 insertions(+), 79 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 352914e4..e2a1961b 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -8,7 +8,6 @@ from datetime import timedelta from django import forms from django.forms.models import BaseInlineFormSet -from django.db.models import Q from django.utils import timezone from bda.models import Attribution, Spectacle diff --git a/bda/models.py b/bda/models.py index f67807c7..27c57d21 100644 --- a/bda/models.py +++ b/bda/models.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import calendar import random from datetime import timedelta @@ -108,7 +104,7 @@ class Spectacle(models.Model): mails_data = [ ( member[0].email, - {'member': member[0],'nb_attr': member[1], 'show': self} + {'member': member[0], 'nb_attr': member[1], 'show': self} ) for member in members.values() ] diff --git a/bda/views.py b/bda/views.py index 24b83c86..5355a45b 100644 --- a/bda/views.py +++ b/bda/views.py @@ -5,7 +5,13 @@ from __future__ import print_function from __future__ import unicode_literals import random -from custommail.utils import send_mass_custom_mail, send_custom_mail +import hashlib +import time +from datetime import timedelta + +from custommail.utils import ( + send_mass_custom_mail, send_custom_mail, render_mail +) from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required @@ -16,15 +22,10 @@ from django.forms.models import inlineformset_factory from django.http import HttpResponseBadRequest, HttpResponseRedirect from django.core.urlresolvers import reverse from django.conf import settings -import hashlib -from django.template import loader from django.utils import timezone from django.views.generic.list import ListView -import time -from datetime import timedelta - from gestioncof.decorators import cof_required, buro_required from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\ Tirage, SpectacleRevente @@ -230,8 +231,8 @@ def do_tirage(request, tirage_id): # À partir d'ici, le tirage devient effectif Attribution.objects.filter(spectacle__tirage=tirage_elt).delete() tirage_elt.tokens += "%s\n\"\"\"%s\"\"\"\n" % ( - timezone.now().strftime("%y-%m-%d %H:%M:%S"), - form.cleaned_data['token']) + timezone.now().strftime("%y-%m-%d %H:%M:%S"), + form.cleaned_data['token']) tirage_elt.enable_do_tirage = False tirage_elt.save() Attribution.objects.bulk_create([ @@ -354,15 +355,15 @@ def revente(request, tirage_id): annulform = AnnulForm(participant, prefix='annul') overdue = participant.attribution_set.filter( - spectacle__date__gte=timezone.now(), - revente__isnull=False, - revente__seller=participant, - revente__date__lte=timezone.now()-timedelta(hours=1)).filter( + spectacle__date__gte=timezone.now(), + revente__isnull=False, + revente__seller=participant, + revente__date__lte=timezone.now()-timedelta(hours=1)).filter( Q(revente__soldTo__isnull=True) | Q(revente__soldTo=participant)) sold = participant.attribution_set.filter( - spectacle__date__gte=timezone.now(), - revente__isnull=False, - revente__soldTo__isnull=False) + spectacle__date__gte=timezone.now(), + revente__isnull=False, + revente__soldTo__isnull=False) return render(request, "bda-revente.html", {'tirage': tirage, 'overdue': overdue, "sold": sold, @@ -372,7 +373,7 @@ def revente(request, tirage_id): @login_required def revente_interested(request, revente_id): revente = get_object_or_404(SpectacleRevente, id=revente_id) - participant, created = Participant.objects.get_or_create( + participant, _ = Participant.objects.get_or_create( user=request.user, tirage=revente.attribution.spectacle.tirage) if (timezone.now() < revente.date + timedelta(hours=1)) or revente.shotgun: return render(request, "bda-wrongtime.html", @@ -387,8 +388,8 @@ def revente_interested(request, revente_id): @login_required def list_revente(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - participant, created = Participant.objects.get_or_create( - user=request.user, tirage=tirage) + participant, _ = Participant.objects.get_or_create( + user=request.user, tirage=tirage) deja_revente = False success = False inscrit_revente = False @@ -400,7 +401,7 @@ def list_revente(request, tirage_id): participant.save() for spectacle in choices: qset = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle) + attribution__spectacle=spectacle) if qset.filter(shotgun=True, soldTo__isnull=True).exists(): # Une place est disponible au shotgun, on suggère à # l'utilisateur d'aller la récupérer @@ -422,24 +423,24 @@ def list_revente(request, tirage_id): success = True else: form = InscriptionReventeForm( - tirage, - initial={'spectacles': participant.choicesrevente.all()}) + tirage, + initial={'spectacles': participant.choicesrevente.all()}) return render(request, "liste-reventes.html", {"form": form, - "deja_revente": deja_revente, "success": success, - "inscrit_revente": inscrit_revente}) + "deja_revente": deja_revente, "success": success, + "inscrit_revente": inscrit_revente}) @login_required def buy_revente(request, spectacle_id): spectacle = get_object_or_404(Spectacle, id=spectacle_id) tirage = spectacle.tirage - participant, created = Participant.objects.get_or_create( - user=request.user, tirage=tirage) + participant, _ = Participant.objects.get_or_create( + user=request.user, tirage=tirage) reventes = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle, - soldTo__isnull=True) + attribution__spectacle=spectacle, + soldTo__isnull=True) # Si l'utilisateur veut racheter une place qu'il est en train de revendre, # on supprime la revente en question. @@ -482,13 +483,13 @@ def buy_revente(request, spectacle_id): def revente_shotgun(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) spectacles = tirage.spectacle_set.filter( - date__gte=timezone.now()) + date__gte=timezone.now()) shotgun = [] for spectacle in spectacles: reventes = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle, - shotgun=True, - soldTo__isnull=True) + attribution__spectacle=spectacle, + shotgun=True, + soldTo__isnull=True) if reventes.exists(): shotgun.append(spectacle) @@ -557,7 +558,7 @@ def send_rappel(request, spectacle_id): 'show': show, 'nb_attr': 1 }) - exemple_mail_2place = render_mail('bda-rappel', { + exemple_mail_2places = render_mail('bda-rappel', { 'member': request.user, 'show': show, 'nb_attr': 2 @@ -589,5 +590,5 @@ def descriptions_spectacles(request, tirage_id): shows_qs = shows_qs.filter(location__id=int(location_id)) except ValueError: return HttpResponseBadRequest( - "La variable GET 'location' doit contenir un entier") + "La variable GET 'location' doit contenir un entier") return render(request, 'descriptions.html', {'shows': shows_qs.all()}) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 9474a087..e42ed6ae 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from datetime import datetime +import base64 +import json -from custommail.utils import send_custom_mail, render_mail +from custommail.utils import render_mail +from captcha.fields import ReCaptchaField from django.shortcuts import render, get_object_or_404, redirect +from django.core import mail from django.forms import ModelForm from django import forms from django.forms.models import inlineformset_factory, BaseInlineFormSet @@ -14,7 +16,6 @@ from django.contrib.auth.models import User from django.views.generic import ListView from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt -from django.template import loader from django.conf import settings from django.contrib.auth.decorators import login_required from django.db.models import Min @@ -26,12 +27,6 @@ from gestioncof.petits_cours_models import PetitCoursDemande, \ from gestioncof.decorators import buro_required from gestioncof.shared import lock_table, unlock_tables -from captcha.fields import ReCaptchaField - -from datetime import datetime -import base64 -import json - class DemandeListView(ListView): model = PetitCoursDemande @@ -148,7 +143,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for, "mainmail": mainmail, "attribdata": base64.b64encode(json.dumps(attribdata) - .encode('utf_8')), + .encode('utf_8')), "redo": redo, "errors": errors, }) @@ -286,14 +281,14 @@ def _traitement_post(request, demande): replyto = settings.MAIL_DATA['petits_cours']['REPLYTO'] mails_to_send = [] for (user, msg) in proposed_mails: - msg = EmailMessage("Petits cours ENS par le COF", msg, - frommail, [user.email], - [bccaddress], headers={'Reply-To': replyto}) + msg = mail.EmailMessage("Petits cours ENS par le COF", msg, + frommail, [user.email], + [bccaddress], headers={'Reply-To': replyto}) mails_to_send.append(msg) - mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail, - frommail, [demande.email], - [bccaddress], - headers={'Reply-To': replyto})) + mails_to_send.append(mail.EmailMessage("Cours particuliers ENS", mainmail, + frommail, [demande.email], + [bccaddress], + headers={'Reply-To': replyto})) connection = mail.get_connection(fail_silently=True) connection.send_messages(mails_to_send) lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User) diff --git a/gestioncof/shared.py b/gestioncof/shared.py index 988b93ee..63aceae5 100644 --- a/gestioncof/shared.py +++ b/gestioncof/shared.py @@ -9,10 +9,7 @@ from django.conf import settings from django_cas_ng.backends import CASBackend from django_cas_ng.utils import get_cas_client from django.contrib.auth import get_user_model -from django.contrib.auth.models import User as DjangoUser from django.db import connection -from django.core.mail import send_mail -from django.template import Template, Context from gestioncof.models import CofProfile @@ -73,9 +70,9 @@ class COFCASBackend(CASBackend): def context_processor(request): '''Append extra data to the context of the given request''' data = { - "user": request.user, - "site": Site.objects.get_current(), - } + "user": request.user, + "site": Site.objects.get_current(), + } return data diff --git a/gestioncof/views.py b/gestioncof/views.py index e086b06c..62f55cc6 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -465,21 +465,21 @@ def registration(request): current_registration.paid = \ (form.cleaned_data['status'] == 'paid') current_registration.save() - if form.event.title == "Mega 15" and created_reg: - field = EventCommentField.objects.get( - event=form.event, name="Commentaires") - try: - comments = EventCommentValue.objects.get( - commentfield=field, - registration=current_registration).content - except EventCommentValue.DoesNotExist: - comments = field.default - # FIXME : il faut faire quelque chose de propre ici, - # par exemple écrire un mail générique pour - # l'inscription aux événements et/ou donner la - # possibilité d'associer un mail aux événements - # send_custom_mail(member, "mega", - # {"remarques": comments}) + # if form.event.title == "Mega 15" and created_reg: + # field = EventCommentField.objects.get( + # event=form.event, name="Commentaires") + # try: + # comments = EventCommentValue.objects.get( + # commentfield=field, + # registration=current_registration).content + # except EventCommentValue.DoesNotExist: + # comments = field.default + # FIXME : il faut faire quelque chose de propre ici, + # par exemple écrire un mail générique pour + # l'inscription aux événements et/ou donner la + # possibilité d'associer un mail aux événements + # send_custom_mail(member, "mega", + # {"remarques": comments}) # Enregistrement des inscriptions aux clubs member.clubs.clear() for club in clubs_form.cleaned_data['clubs']: From 298015285a5e4681658b9a9cfce18f0eb359035e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 22 Dec 2016 12:28:03 +0100 Subject: [PATCH 03/13] cleanup et nouvelle implem de custommail --- bda/forms.py | 1 - bda/models.py | 102 +++++++++++++------------------ bda/views.py | 85 +++++++++++++------------- gestioncof/petits_cours_views.py | 40 ++++++------ gestioncof/shared.py | 9 +-- gestioncof/views.py | 33 +++++----- 6 files changed, 120 insertions(+), 150 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 352914e4..e2a1961b 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -8,7 +8,6 @@ from datetime import timedelta from django import forms from django.forms.models import BaseInlineFormSet -from django.db.models import Q from django.utils import timezone from bda.models import Attribution, Spectacle diff --git a/bda/models.py b/bda/models.py index f67807c7..a14585ee 100644 --- a/bda/models.py +++ b/bda/models.py @@ -1,13 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import calendar import random from datetime import timedelta -from custommail.utils import send_custom_mail, send_mass_custom_mail +from custommail.shortcuts import send_custom_mail, send_mass_custom_mail from django.contrib.sites.models import Site from django.db import models @@ -105,18 +101,14 @@ class Spectacle(models.Model): # members[0] = ['BdA', 1, 'bda@ens.fr'] # members[-1] = ['BdA', 2, 'bda@ens.fr'] # On écrit un mail personnalisé à chaque participant - mails_data = [ - ( - member[0].email, - {'member': member[0],'nb_attr': member[1], 'show': self} - ) + datatuple = [( + 'bda-rappel', + {'member': member[0], 'nb_attr': member[1], 'show': self}, + settings.MAIL_DATA['rappels']['FROM'], + [member[0].email]) for member in members.values() ] - send_mass_custom_mail( - 'bda-rappel', - mails_data, - from_email=settings.MAIL_DATA['rappels']['FROM'] - ) + send_mass_custom_mail(datatuple) # On enregistre le fait que l'envoi a bien eu lieu self.rappel_sent = timezone.now() self.save() @@ -252,23 +244,19 @@ class SpectacleRevente(models.Model): BdA-Revente à tous les intéressés. """ inscrits = self.attribution.spectacle.subscribed.select_related('user') - mails_data = [ - ( - participant.user.email, - { - 'member': participant.user, - 'show': self.attribution.spectacle, - 'revente': self, - 'site': Site.objects.get_current() - } - ) + datatuple = [( + 'bda-revente', + { + 'member': participant.user, + 'show': self.attribution.spectacle, + 'revente': self, + 'site': Site.objects.get_current() + }, + settings.MAIL_DATA['revente']['FROM'], + [participant.user.email]) for participant in inscrits ] - send_mass_custom_mail( - "bda-revente", - mails_data, - from_email=settings.MAIL_DATA['revente']['FROM'], - ) + send_mass_custom_mail(datatuple) self.notif_sent = True self.save() @@ -278,22 +266,18 @@ class SpectacleRevente(models.Model): leur indiquer qu'il est désormais disponible au shotgun. """ inscrits = self.attribution.spectacle.subscribed.select_related('user') - mails_data = [ - ( - participant.user.email, - { - 'member': participant.user, - 'show': self.attribution.spectacle, - 'site': Site.objects.get_current(), - } - ) + datatuple = [( + 'bda-shotgun', + { + 'member': participant.user, + 'show': self.attribution.spectacle, + 'site': Site.objects.get_current(), + }, + settings.MAIL_DATA['revente']['FROM'], + [participant.user.email]) for participant in inscrits ] - send_mass_custom_mail( - "bda-shotgun", - mails_data, - from_email=settings.MAIL_DATA['revente']['FROM'] - ) + send_mass_custom_mail(datatuple) self.notif_sent = True # Flag inutile, sauf si l'horloge interne merde self.tirage_done = True @@ -320,35 +304,31 @@ class SpectacleRevente(models.Model): 'show': spectacle, } send_custom_mail( - winner.user.email, 'bda-revente-winner', + [winner.user.email], context=context, from_email=settings.MAIL_DATA['revente']['FROM'] ) send_custom_mail( - seller.user.email, 'bda-revente-seller', + [seller.user.email], context=context, from_email=settings.MAIL_DATA['revente']['FROM'] ) # Envoie un mail aux perdants - mails_data = [ - ( - inscrit.user.email, - { - 'acheteur': inscrit.user, - 'vendeur': seller.user, - 'show': spectacle - } - ) - for inscrit in inscrits if inscrit == winner - ] - send_mass_custom_mail( + datatuple = [( 'bda-revente-loser', - mails_data, - from_email=settings.MAIL_DATA['revente']['FROM'] - ) + { + 'acheteur': inscrit.user, + 'vendeur': seller.user, + 'show': spectacle + }, + settings.MAIL_DATA['revente']['FROM'], + [inscrit.user.email]) + for inscrit in inscrits if inscrit != winner + ] + send_mass_custom_mail(datatuple) # Si personne ne veut de la place, elle part au shotgun else: self.shotgun = True diff --git a/bda/views.py b/bda/views.py index 24b83c86..4f0d717d 100644 --- a/bda/views.py +++ b/bda/views.py @@ -5,7 +5,13 @@ from __future__ import print_function from __future__ import unicode_literals import random -from custommail.utils import send_mass_custom_mail, send_custom_mail +import hashlib +import time +from datetime import timedelta + +from custommail.shortcuts import ( + send_mass_custom_mail, send_custom_mail, render_custom_mail +) from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required @@ -16,15 +22,10 @@ from django.forms.models import inlineformset_factory from django.http import HttpResponseBadRequest, HttpResponseRedirect from django.core.urlresolvers import reverse from django.conf import settings -import hashlib -from django.template import loader from django.utils import timezone from django.views.generic.list import ListView -import time -from datetime import timedelta - from gestioncof.decorators import cof_required, buro_required from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\ Tirage, SpectacleRevente @@ -230,8 +231,8 @@ def do_tirage(request, tirage_id): # À partir d'ici, le tirage devient effectif Attribution.objects.filter(spectacle__tirage=tirage_elt).delete() tirage_elt.tokens += "%s\n\"\"\"%s\"\"\"\n" % ( - timezone.now().strftime("%y-%m-%d %H:%M:%S"), - form.cleaned_data['token']) + timezone.now().strftime("%y-%m-%d %H:%M:%S"), + form.cleaned_data['token']) tirage_elt.enable_do_tirage = False tirage_elt.save() Attribution.objects.bulk_create([ @@ -276,7 +277,7 @@ def revente(request, tirage_id): resellform = ResellForm(participant, request.POST, prefix='resell') annulform = AnnulForm(participant, prefix='annul') if resellform.is_valid(): - mails_data = [] + datatuple = [] attributions = resellform.cleaned_data["attributions"] with transaction.atomic(): for attribution in attributions: @@ -296,13 +297,13 @@ def revente(request, tirage_id): 'show': attribution.spectacle, 'revente': revente } - mails_data.append(participant.user.email, context) + datatuple.append(( + 'bda-revente-new', context, + settings.MAIL_DATA['revente']['FROM'], + [participant.user.email] + )) revente.save() - send_mass_custom_mail( - 'bda-revente-new', - mails_data, - from_email=settings.MAIL_DATA['revente']['FROM'] - ) + send_mass_custom_mail(datatuple) # On annule une revente elif 'annul' in request.POST: annulform = AnnulForm(participant, request.POST, prefix='annul') @@ -354,15 +355,15 @@ def revente(request, tirage_id): annulform = AnnulForm(participant, prefix='annul') overdue = participant.attribution_set.filter( - spectacle__date__gte=timezone.now(), - revente__isnull=False, - revente__seller=participant, - revente__date__lte=timezone.now()-timedelta(hours=1)).filter( + spectacle__date__gte=timezone.now(), + revente__isnull=False, + revente__seller=participant, + revente__date__lte=timezone.now()-timedelta(hours=1)).filter( Q(revente__soldTo__isnull=True) | Q(revente__soldTo=participant)) sold = participant.attribution_set.filter( - spectacle__date__gte=timezone.now(), - revente__isnull=False, - revente__soldTo__isnull=False) + spectacle__date__gte=timezone.now(), + revente__isnull=False, + revente__soldTo__isnull=False) return render(request, "bda-revente.html", {'tirage': tirage, 'overdue': overdue, "sold": sold, @@ -372,7 +373,7 @@ def revente(request, tirage_id): @login_required def revente_interested(request, revente_id): revente = get_object_or_404(SpectacleRevente, id=revente_id) - participant, created = Participant.objects.get_or_create( + participant, _ = Participant.objects.get_or_create( user=request.user, tirage=revente.attribution.spectacle.tirage) if (timezone.now() < revente.date + timedelta(hours=1)) or revente.shotgun: return render(request, "bda-wrongtime.html", @@ -387,8 +388,8 @@ def revente_interested(request, revente_id): @login_required def list_revente(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - participant, created = Participant.objects.get_or_create( - user=request.user, tirage=tirage) + participant, _ = Participant.objects.get_or_create( + user=request.user, tirage=tirage) deja_revente = False success = False inscrit_revente = False @@ -400,7 +401,7 @@ def list_revente(request, tirage_id): participant.save() for spectacle in choices: qset = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle) + attribution__spectacle=spectacle) if qset.filter(shotgun=True, soldTo__isnull=True).exists(): # Une place est disponible au shotgun, on suggère à # l'utilisateur d'aller la récupérer @@ -422,24 +423,24 @@ def list_revente(request, tirage_id): success = True else: form = InscriptionReventeForm( - tirage, - initial={'spectacles': participant.choicesrevente.all()}) + tirage, + initial={'spectacles': participant.choicesrevente.all()}) return render(request, "liste-reventes.html", {"form": form, - "deja_revente": deja_revente, "success": success, - "inscrit_revente": inscrit_revente}) + "deja_revente": deja_revente, "success": success, + "inscrit_revente": inscrit_revente}) @login_required def buy_revente(request, spectacle_id): spectacle = get_object_or_404(Spectacle, id=spectacle_id) tirage = spectacle.tirage - participant, created = Participant.objects.get_or_create( - user=request.user, tirage=tirage) + participant, _ = Participant.objects.get_or_create( + user=request.user, tirage=tirage) reventes = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle, - soldTo__isnull=True) + attribution__spectacle=spectacle, + soldTo__isnull=True) # Si l'utilisateur veut racheter une place qu'il est en train de revendre, # on supprime la revente en question. @@ -464,8 +465,8 @@ def buy_revente(request, spectacle_id): 'vendeur': revente.seller.user } send_custom_mail( - revente.seller.user.email, 'bda-buy-shotgun', + [revente.seller.user.email], context=context, from_email='bda@ens.fr' ) @@ -482,13 +483,13 @@ def buy_revente(request, spectacle_id): def revente_shotgun(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) spectacles = tirage.spectacle_set.filter( - date__gte=timezone.now()) + date__gte=timezone.now()) shotgun = [] for spectacle in spectacles: reventes = SpectacleRevente.objects.filter( - attribution__spectacle=spectacle, - shotgun=True, - soldTo__isnull=True) + attribution__spectacle=spectacle, + shotgun=True, + soldTo__isnull=True) if reventes.exists(): shotgun.append(spectacle) @@ -552,12 +553,12 @@ def unpaid(request, tirage_id): def send_rappel(request, spectacle_id): show = get_object_or_404(Spectacle, id=spectacle_id) # Mails d'exemples - exemple_mail_1place = render_mail('bda-rappel', { + exemple_mail_1place = render_custom_mail('bda-rappel', { 'member': request.user, 'show': show, 'nb_attr': 1 }) - exemple_mail_2place = render_mail('bda-rappel', { + exemple_mail_2places = render_custom_mail('bda-rappel', { 'member': request.user, 'show': show, 'nb_attr': 2 @@ -589,5 +590,5 @@ def descriptions_spectacles(request, tirage_id): shows_qs = shows_qs.filter(location__id=int(location_id)) except ValueError: return HttpResponseBadRequest( - "La variable GET 'location' doit contenir un entier") + "La variable GET 'location' doit contenir un entier") return render(request, 'descriptions.html', {'shows': shows_qs.all()}) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 9474a087..973db315 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -from custommail.utils import send_custom_mail, render_mail +from datetime import datetime +import base64 +import json +from captcha.fields import ReCaptchaField +from custommail.shortcuts import render_custom_mail from django.shortcuts import render, get_object_or_404, redirect +from django.core import mail from django.forms import ModelForm from django import forms from django.forms.models import inlineformset_factory, BaseInlineFormSet @@ -14,7 +15,6 @@ from django.contrib.auth.models import User from django.views.generic import ListView from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt -from django.template import loader from django.conf import settings from django.contrib.auth.decorators import login_required from django.db.models import Min @@ -26,12 +26,6 @@ from gestioncof.petits_cours_models import PetitCoursDemande, \ from gestioncof.decorators import buro_required from gestioncof.shared import lock_table, unlock_tables -from captcha.fields import ReCaptchaField - -from datetime import datetime -import base64 -import json - class DemandeListView(ListView): model = PetitCoursDemande @@ -131,7 +125,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for, proposed_for = proposed_for.items() attribdata = list(attribdata.items()) proposed_mails = _generate_eleve_email(demande, proposed_for) - mainmail = render_mail("petits-cours-mail-demandeur", { + mainmail = render_custom_mail("petits-cours-mail-demandeur", { "proposals": proposals, "unsatisfied": unsatisfied, "extra": @@ -148,7 +142,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for, "mainmail": mainmail, "attribdata": base64.b64encode(json.dumps(attribdata) - .encode('utf_8')), + .encode('utf_8')), "redo": redo, "errors": errors, }) @@ -158,7 +152,7 @@ def _generate_eleve_email(demande, proposed_for): return [ ( user, - render_mail('petit-cours-mail-eleve', { + render_custom_mail('petit-cours-mail-eleve', { "demande": demande, "matieres": matieres })[1] @@ -276,7 +270,7 @@ def _traitement_post(request, demande): proposals_list = proposals.items() proposed_for = proposed_for.items() proposed_mails = _generate_eleve_email(demande, proposed_for) - mainmail = render_mail("petits-cours-mail-demandeur", { + mainmail = render_custom_mail("petits-cours-mail-demandeur", { "proposals": proposals_list, "unsatisfied": unsatisfied, "extra": extra, @@ -286,14 +280,14 @@ def _traitement_post(request, demande): replyto = settings.MAIL_DATA['petits_cours']['REPLYTO'] mails_to_send = [] for (user, msg) in proposed_mails: - msg = EmailMessage("Petits cours ENS par le COF", msg, - frommail, [user.email], - [bccaddress], headers={'Reply-To': replyto}) + msg = mail.EmailMessage("Petits cours ENS par le COF", msg, + frommail, [user.email], + [bccaddress], headers={'Reply-To': replyto}) mails_to_send.append(msg) - mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail, - frommail, [demande.email], - [bccaddress], - headers={'Reply-To': replyto})) + mails_to_send.append(mail.EmailMessage("Cours particuliers ENS", mainmail, + frommail, [demande.email], + [bccaddress], + headers={'Reply-To': replyto})) connection = mail.get_connection(fail_silently=True) connection.send_messages(mails_to_send) lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User) diff --git a/gestioncof/shared.py b/gestioncof/shared.py index 988b93ee..63aceae5 100644 --- a/gestioncof/shared.py +++ b/gestioncof/shared.py @@ -9,10 +9,7 @@ from django.conf import settings from django_cas_ng.backends import CASBackend from django_cas_ng.utils import get_cas_client from django.contrib.auth import get_user_model -from django.contrib.auth.models import User as DjangoUser from django.db import connection -from django.core.mail import send_mail -from django.template import Template, Context from gestioncof.models import CofProfile @@ -73,9 +70,9 @@ class COFCASBackend(CASBackend): def context_processor(request): '''Append extra data to the context of the given request''' data = { - "user": request.user, - "site": Site.objects.get_current(), - } + "user": request.user, + "site": Site.objects.get_current(), + } return data diff --git a/gestioncof/views.py b/gestioncof/views.py index e086b06c..3b27f915 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -8,7 +8,7 @@ import unicodecsv import uuid from datetime import timedelta from icalendar import Calendar, Event as Vevent -from custommail.utils import send_custom_mail +from custommail.shortcuts import send_custom_mail from django.shortcuts import redirect, get_object_or_404, render from django.http import Http404, HttpResponse, HttpResponseForbidden @@ -439,7 +439,7 @@ def registration(request): profile = profile_form.save() if profile.is_cof and not was_cof: send_custom_mail( - member.email, "welcome", + "welcome", [member.email], context={'member': member}, from_email='cof@ens.fr' ) @@ -465,21 +465,20 @@ def registration(request): current_registration.paid = \ (form.cleaned_data['status'] == 'paid') current_registration.save() - if form.event.title == "Mega 15" and created_reg: - field = EventCommentField.objects.get( - event=form.event, name="Commentaires") - try: - comments = EventCommentValue.objects.get( - commentfield=field, - registration=current_registration).content - except EventCommentValue.DoesNotExist: - comments = field.default - # FIXME : il faut faire quelque chose de propre ici, - # par exemple écrire un mail générique pour - # l'inscription aux événements et/ou donner la - # possibilité d'associer un mail aux événements - # send_custom_mail(member, "mega", - # {"remarques": comments}) + # if form.event.title == "Mega 15" and created_reg: + # field = EventCommentField.objects.get( + # event=form.event, name="Commentaires") + # try: + # comments = EventCommentValue.objects.get( + # commentfield=field, + # registration=current_registration).content + # except EventCommentValue.DoesNotExist: + # comments = field.default + # FIXME : il faut faire quelque chose de propre ici, + # par exemple écrire un mail générique pour + # l'inscription aux événements et/ou donner la + # possibilité d'associer un mail aux événements + # send_custom_mail(...) # Enregistrement des inscriptions aux clubs member.clubs.clear() for club in clubs_form.cleaned_data['clubs']: From b39806e171c393d1c398a79adc973a8c5c075203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 22 Dec 2016 20:59:38 +0100 Subject: [PATCH 04/13] Migration et chargement des emails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - La migration qui supprime le vieux modèle gestioncof.CustomMail est ajoutée - Les mails de GestioCOF sont dans un json qui est chargé par la commande `python manage.py syncmails` Voir l'aide de la commande pour plus 'information --- bda/admin.py | 77 +-- gestioncof/management/__init__.py | 0 gestioncof/management/commands/__init__.py | 0 gestioncof/management/commands/syncmails.py | 78 +++ gestioncof/management/data/custommail.json | 587 ++++++++++++++++++ .../migrations/0009_delete_custommail.py | 16 + 6 files changed, 694 insertions(+), 64 deletions(-) create mode 100644 gestioncof/management/__init__.py create mode 100644 gestioncof/management/commands/__init__.py create mode 100644 gestioncof/management/commands/syncmails.py create mode 100644 gestioncof/management/data/custommail.json create mode 100644 gestioncof/migrations/0009_delete_custommail.py diff --git a/bda/admin.py b/bda/admin.py index 0e9b683b..fc10c326 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +import autocomplete_light +from datetime import timedelta +from custommail.shortcuts import send_mass_custom_mail -from django.core.mail import send_mail from django.contrib import admin from django.db.models import Sum, Count from django.template.defaultfilters import pluralize @@ -13,10 +12,6 @@ from django import forms from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente -from datetime import timedelta - -import autocomplete_light - class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle @@ -72,66 +67,20 @@ class ParticipantAdmin(admin.ModelAdmin): readonly_fields = ("total",) def send_attribs(self, request, queryset): + datatuple = [] for member in queryset.all(): attribs = member.attributions.all() + context = {'member': member.user} + shortname = "" if len(attribs) == 0: - mail = """Cher-e %s, - -Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as -obtenu aucune place. - -Nous proposons cependant de nombreuses offres hors-tirage tout au long de -l'année, et nous t'invitons à nous contacter si l'une d'entre elles -t'intéresse ! --- -Le Bureau des Arts - -""" - name = member.user.get_full_name() - mail = mail % name + shortname = "bda-attributions-decus" else: - mail = """Cher-e %s, - -Tu t'es inscrit-e pour le tirage au sort du BdA. Tu as été sélectionné-e -pour les spectacles suivants : - -%s - -*Paiement* -L'intégralité de ces places de spectacles est à régler dès maintenant et AVANT -le %s, au bureau du COF pendant les heures de permanences (du lundi au vendredi -entre 12h et 14h, et entre 18h et 20h). Des facilités de paiement sont bien -évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement, -ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas -venir payer au bureau, merci de nous contacter par mail. - -*Mode de retrait des places* -Au moment du paiement, certaines places vous seront remises directement, -d'autres seront à récupérer au cours de l'année, d'autres encore seront -nominatives et à retirer le soir même dans les theâtres correspondants. -Pour chaque spectacle, vous recevrez un mail quelques jours avant la -représentation vous indiquant le mode de retrait. - -Nous vous rappelons que l'obtention de places du BdA vous engage à -respecter les règles de fonctionnement : -http://www.cof.ens.fr/bda/?page_id=1370 -Le système de revente des places via les mails BdA-revente sera très -prochainement disponible, directement sur votre compte GestioCOF. - -En vous souhaitant de très beaux spectacles tout au long de l'année, --- -Le Bureau des Arts -""" - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += "- 1 place pour %s\n" % attrib - deadline = member.tirage.fermeture + timedelta(days=7) - mail = mail % (name, attribs_text, - deadline.strftime('%d %b %Y')) - send_mail("Résultats du tirage au sort", mail, - "bda@ens.fr", [member.user.email], - fail_silently=True) + shortname = "bda-attributions" + context['places'] = attribs + print(context) + datatuple.append((shortname, context, "bda@ens.fr", + [member.user.email])) + send_mass_custom_mail(datatuple) count = len(queryset.all()) if count == 1: message_bit = "1 membre a" diff --git a/gestioncof/management/__init__.py b/gestioncof/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gestioncof/management/commands/__init__.py b/gestioncof/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py new file mode 100644 index 00000000..6ce1fd6e --- /dev/null +++ b/gestioncof/management/commands/syncmails.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +""" +Import des mails de GestioCOF dans la base de donnée +""" + +import json +import os +from custommail.models import VariableType, CustomMail, CustomMailVariable + +from django.core.management.base import BaseCommand +from django.contrib.contenttypes.models import ContentType + + +class Command(BaseCommand): + help = ("Va chercher les données mails de GestioCOF stocké au format json " + "dans /gestioncof/management/data/custommails.json. Le format des " + "données est celui donné par la commande :" + " `python manage.py dumpdata custommail --natural-foreign` " + "La bonne façon de mettre à jour ce fichier est donc de le " + "charger à l'aide de syncmails, le faire les modifications à " + "l'aide de l'interface administration et/ou du shell puis de le " + "remplacer par le nouveau résultat de la commande précédente.") + + def handle(self, *args, **options): + path = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + 'data', 'custommail.json') + with open(path, 'r') as jsonfile: + mail_data = json.load(jsonfile) + + # On se souvient à quel objet correspond quel pk du json + assoc = {'types': {}, 'mails': {}} + status = {'synced': 0, 'unchanged': 0} + + for obj in mail_data: + model = obj['model'] + fields = obj['fields'] + + # Pour les trois types d'objets : + # - On récupère les objets référencés par les clefs étrangères + # - On crée l'objet si nécessaire + # - On le stocke éventuellement dans les deux dictionnaires définis + # plus haut + + # Variable types + if model == 'custommail.variabletype': + fields['inner1'] = assoc['types'].get(fields['inner1']) + fields['inner2'] = assoc['types'].get(fields['inner2']) + if fields['typ'] == 'model': + fields['content_type'] = ( + ContentType.objects + .get_by_natural_key(*fields['content_type']) + ) + var_type, _ = VariableType.objects.get_or_create(**fields) + assoc['types'][obj['pk']] = var_type + + # Custom mails + if model == 'custommail.custommail': + mail, created = CustomMail.objects.get_or_create(**fields) + assoc['mails'][obj['pk']] = mail + if created: + self.stdout.write( + 'SYNCED {:s}'.format(fields['shortname'])) + status['synced'] += 1 + else: + status['unchanged'] += 1 + + # Variables + if model == 'custommail.custommailvariable': + fields['custommail'] = assoc['mails'].get(fields['custommail']) + fields['typ'] = assoc['types'].get(fields['typ']) + CustomMailVariable.objects.get_or_create(**fields) + + # C'est agréable d'avoir le résultat affiché + self.stdout.write( + '{synced:d} mails synchronized {unchanged:d} unchanged' + .format(**status) + ) diff --git a/gestioncof/management/data/custommail.json b/gestioncof/management/data/custommail.json new file mode 100644 index 00000000..0f81744c --- /dev/null +++ b/gestioncof/management/data/custommail.json @@ -0,0 +1,587 @@ +[ +{ + "model": "custommail.variabletype", + "pk": 1, + "fields": { + "content_type": [ + "auth", + "user" + ], + "inner1": null, + "typ": "model", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 2, + "fields": { + "content_type": null, + "inner1": null, + "typ": "int", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 3, + "fields": { + "content_type": [ + "bda", + "spectacle" + ], + "inner1": null, + "typ": "model", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 4, + "fields": { + "content_type": [ + "bda", + "spectaclerevente" + ], + "inner1": null, + "typ": "model", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 5, + "fields": { + "content_type": [ + "sites", + "site" + ], + "inner1": null, + "typ": "model", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 6, + "fields": { + "content_type": [ + "gestioncof", + "petitcoursdemande" + ], + "inner1": null, + "typ": "model", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 7, + "fields": { + "content_type": null, + "inner1": null, + "typ": "list", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 8, + "fields": { + "content_type": null, + "inner1": 1, + "typ": "list", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 9, + "fields": { + "content_type": null, + "inner1": null, + "typ": "pair", + "inner2": 8 + } +}, +{ + "model": "custommail.variabletype", + "pk": 10, + "fields": { + "content_type": null, + "inner1": 9, + "typ": "list", + "inner2": null + } +}, +{ + "model": "custommail.variabletype", + "pk": 11, + "fields": { + "content_type": null, + "inner1": 3, + "typ": "list", + "inner2": null + } +}, +{ + "model": "custommail.custommail", + "pk": 1, + "fields": { + "shortname": "welcome", + "subject": "Bienvenue au COF", + "description": "Mail de bienvenue au COF envoy\u00e9 automatiquement \u00e0 l'inscription d'un nouveau membre", + "body": "Bonjour {{ member.first_name }} et bienvenue au COF !\r\n\r\nTu trouveras plein de trucs cool sur le site du COF : https://www.cof.ens.fr/ et notre page Facebook : https://www.facebook.com/cof.ulm\r\nEt n'oublie pas d'aller d\u00e9couvrir GestioCOF, la plateforme de gestion du COF !\r\nSi tu as des questions, tu peux nous envoyer un mail \u00e0 cof@ens.fr (on aime le spam), ou passer nous voir au Bur\u00f4 pr\u00e8s de la Cour\u00f4 du lundi au vendredi de 12h \u00e0 14h et de 18h \u00e0 20h.\r\n\r\nRetrouvez les \u00e9v\u00e8nements de rentr\u00e9e pour les conscrit.e.s et les vieux/vieilles organis\u00e9s par le COF et ses clubs ici : http://www.cof.ens.fr/depot/Rentree.pdf \r\n\r\nAmicalement,\r\n\r\nTon COF qui t'aime." + } +}, +{ + "model": "custommail.custommail", + "pk": 2, + "fields": { + "shortname": "bda-rappel", + "subject": "{{ show }}", + "description": "Mail de rappel pour les spectacles BdA", + "body": "Bonjour {{ member.first_name }},\r\n\r\nNous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:\"une place,deux places\" }}\r\npour {{ show.title }}, le {{ show.date }} au {{ show.location }}. N'oublie pas de t'y rendre !\r\n{% if nb_attr == 2 %}\r\nTu as obtenu deux places pour ce spectacle. Nous te rappelons que\r\nces places sont strictement r\u00e9serv\u00e9es aux personnes de moins de 28 ans.\r\n{% endif %}\r\n{% if show.listing %}Pour ce spectacle, tu as re\u00e7u des places sur\r\nlisting. Il te faudra donc te rendre 15 minutes en avance sur les lieux de la repr\u00e9sentation\r\npour retirer {{ nb_attr|pluralize:\"ta place,tes places\" }}.\r\n{% else %}Pour assister \u00e0 ce spectacle, tu dois pr\u00e9senter les billets qui ont\r\n\u00e9t\u00e9 distribu\u00e9s au bur\u00f4.\r\n{% endif %}\r\n\r\nSi tu ne peux plus assister \u00e0 cette repr\u00e9sentation, tu peux\r\nrevendre ta place via BdA-revente, accessible directement sur\r\nGestioCOF (lien \"revendre une place du premier tirage\" sur la page\r\nd'accueil https://www.cof.ens.fr/gestion/).\r\n\r\nEn te souhaitant un excellent spectacle,\r\n\r\nLe Bureau des Arts" + } +}, +{ + "model": "custommail.custommail", + "pk": 3, + "fields": { + "shortname": "bda-revente", + "subject": "{{ show }}", + "description": "Notification envoy\u00e9e \u00e0 toutes les personnes int\u00e9ress\u00e9es par un spectacle pour le signaler qu'une place vient d'\u00eatre mise en vente.", + "body": "Bonjour {{ member.first_name }}\r\n\r\nUne place pour le spectacle {{ show.title }} ({{ show.date }})\r\na \u00e9t\u00e9 post\u00e9e sur BdA-Revente.\r\n\r\nSi ce spectacle t'int\u00e9resse toujours, merci de nous le signaler en cliquant\r\nsur ce lien : http://{{ site }}{% url \"bda-revente-interested\" revente.id %}.\r\nDans le cas o\u00f9 plusieurs personnes seraient int\u00e9ress\u00e9es, nous proc\u00e8derons \u00e0\r\nun tirage au sort le {{ revente.date_tirage|date:\"DATE_FORMAT\" }}.\r\n\r\nChaleureusement,\r\nLe BdA" + } +}, +{ + "model": "custommail.custommail", + "pk": 4, + "fields": { + "shortname": "bda-shotgun", + "subject": "{{ show }}", + "description": "Notification signalant qu'une place est au shotgun aux personnes int\u00e9ress\u00e9es.", + "body": "Bonjour {{ member.first_name }}\r\n\r\nUne place pour le spectacle {{ show.title }} ({{ show.date }})\r\na \u00e9t\u00e9 post\u00e9e sur BdA-Revente.\r\n\r\nPuisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour\r\ncette place : elle est disponible imm\u00e9diatement \u00e0 l'adresse\r\nhttp://{{ site }}{% url \"bda-buy-revente\" show.id %}, \u00e0 la disposition de tous.\r\n\r\nChaleureusement,\r\nLe BdA" + } +}, +{ + "model": "custommail.custommail", + "pk": 5, + "fields": { + "shortname": "bda-revente-winner", + "subject": "BdA-Revente : {{ show.title }}", + "description": "Mail envoy\u00e9 au gagnant d'un tirage BdA-Revente", + "body": "Bonjour {{ acheteur.first_name }},\r\n\r\nTu as \u00e9t\u00e9 tir\u00e9-e au sort pour racheter une place pour {{ show.title }} le {{ show.date }} ({{ show.location }}) \u00e0 {{ show.price|floatformat:2 }}\u20ac.\r\nTu peux contacter le/la vendeur-se \u00e0 l'adresse {{ vendeur.email }}.\r\n\r\nChaleureusement,\r\nLe BdA" + } +}, +{ + "model": "custommail.custommail", + "pk": 6, + "fields": { + "shortname": "bda-revente-loser", + "subject": "BdA-Revente : {{ show.title }}", + "description": "Notification envoy\u00e9e aux perdants d'un tirage de revente.", + "body": "Bonjour {{ acheteur.first_name }},\r\n\r\nTu t'\u00e9tais inscrit-e pour la revente de la place de {{ vendeur.get_full_name }}\r\npour {{ show.title }}.\r\nMalheureusement, une autre personne a \u00e9t\u00e9 tir\u00e9e au sort pour racheter la place.\r\nTu pourras certainement retenter ta chance pour une autre revente !\r\n\r\n\u00c0 tr\u00e8s bient\u00f4t,\r\nLe Bureau des Arts" + } +}, +{ + "model": "custommail.custommail", + "pk": 7, + "fields": { + "shortname": "bda-revente-seller", + "subject": "BdA-Revente : {{ show.title }}", + "description": "Notification envoy\u00e9e au vendeur d'une place pour lui indiquer qu'elle vient d'\u00eatre attribu\u00e9e", + "body": "Bonjour {{ vendeur.first_name }},\r\n\r\nLa personne tir\u00e9e au sort pour racheter ta place pour {{ show.title }} est {{ acheteur.get_full_name }}.\r\nTu peux le/la contacter \u00e0 l'adresse {{ acheteur.email }}, ou en r\u00e9pondant \u00e0 ce mail.\r\n\r\nChaleureusement,\r\nLe BdA" + } +}, +{ + "model": "custommail.custommail", + "pk": 8, + "fields": { + "shortname": "bda-revente-new", + "subject": "BdA-Revente : {{ show.title }}", + "description": "Notification signalant au vendeur d'une place que sa mise en vente a bien eu lieu et lui donnant quelques informations compl\u00e9mentaires.", + "body": "Bonjour {{ vendeur.first_name }},\r\n\r\nTu t\u2019es bien inscrit-e pour la revente de {{ show.title }}.\r\n\r\n{% with revente.date_tirage as time %}\r\nLe tirage au sort entre tout-e-s les racheteuse-eur-s potentiel-le-s aura lieu\r\nle {{ time|date:\"DATE_FORMAT\" }} \u00e0 {{ time|time:\"TIME_FORMAT\" }} (dans {{time|timeuntil }}).\r\nSi personne ne s\u2019est inscrit pour racheter la place, celle-ci apparaitra parmi\r\nles \u00ab Places disponibles imm\u00e9diatement \u00e0 la revente \u00bb sur GestioCOF.\r\n{% endwith %}\r\n\r\nBonne revente !\r\nLe Bureau des Arts" + } +}, +{ + "model": "custommail.custommail", + "pk": 9, + "fields": { + "shortname": "bda-buy-shotgun", + "subject": "BdA-Revente : {{ show.title }}", + "description": "Mail envoy\u00e9 au revendeur lors d'un achat au shotgun.", + "body": "Bonjour {{ vendeur.first_name }} !\r\n\r\nJe souhaiterais racheter ta place pour {{ show.title }} le {{ show.date }} ({{ show.location }}) \u00e0 {{ show.price|floatformat:2 }}\u20ac.\r\nContacte-moi si tu es toujours int\u00e9ress\u00e9\u00b7e !\r\n\r\n{{ acheteur.get_full_name }} ({{ acheteur.email }})" + } +}, +{ + "model": "custommail.custommail", + "pk": 10, + "fields": { + "shortname": "petit-cours-mail-eleve", + "subject": "Petits cours ENS par le COF", + "description": "Mail envoy\u00e9 aux personnes dont ont a donn\u00e9 les contacts \u00e0 des demandeurs de petits cours", + "body": "Salut,\r\n\r\nLe COF a re\u00e7u une demande de petit cours qui te correspond. Tu es en haut de la liste d'attente donc on a transmis tes coordonn\u00e9es, ainsi que celles de 2 autres qui correspondaient aussi (c'est la vie, on donne les num\u00e9ros 3 par 3 pour que ce soit plus souple). Voici quelques infos sur l'annonce en question :\r\n\r\n\u00a4 Nom : {{ demande.name }}\r\n\r\n\u00a4 P\u00e9riode : {{ demande.quand }}\r\n\r\n\u00a4 Fr\u00e9quence : {{ demande.freq }}\r\n\r\n\u00a4 Lieu (si pr\u00e9f\u00e9r\u00e9) : {{ demande.lieu }}\r\n\r\n\u00a4 Niveau : {{ demande.get_niveau_display }}\r\n\r\n\u00a4 Remarques diverses (d\u00e9sol\u00e9 pour les balises HTML) : {{ demande.remarques }}\r\n\r\n{% if matieres|length > 1 %}\u00a4 Mati\u00e8res :\r\n{% for matiere in matieres %} \u00a4 {{ matiere }}\r\n{% endfor %}{% else %}\u00a4 Mati\u00e8re : {% for matiere in matieres %}{{ matiere }}\r\n{% endfor %}{% endif %}\r\nVoil\u00e0, cette personne te contactera peut-\u00eatre sous peu, tu pourras voir les d\u00e9tails directement avec elle (prix, modalit\u00e9s, ...). Pour indication, 30 Euro/h semble \u00eatre la moyenne.\r\n\r\nSi tu te rends compte qu'en fait tu ne peux pas/plus donner de cours en ce moment, \u00e7a serait cool que tu d\u00e9coches la case \"Recevoir des propositions de petits cours\" sur GestioCOF. Ensuite d\u00e8s que tu voudras r\u00e9appara\u00eetre tu pourras recocher la case et tu seras \u00e0 nouveau sur la liste.\r\n\r\n\u00c0 bient\u00f4t,\r\n\r\n--\r\nLe COF, pour les petits cours" + } +}, +{ + "model": "custommail.custommail", + "pk": 11, + "fields": { + "shortname": "petits-cours-mail-demandeur", + "subject": "Cours particuliers ENS", + "description": "Mail envoy\u00e9 aux personnent qui demandent des petits cours lorsque leur demande est trait\u00e9e.\r\n\r\n(Ne pas toucher \u00e0 {{ extra|safe }})", + "body": "Bonjour,\r\n\r\nJe vous contacte au sujet de votre annonce pass\u00e9e sur le site du COF pour rentrer en contact avec un \u00e9l\u00e8ve normalien pour des cours particuliers. Voici les coordonn\u00e9es d'\u00e9l\u00e8ves qui sont motiv\u00e9s par de tels cours et correspondent aux crit\u00e8res que vous nous aviez transmis :\r\n\r\n{% for matiere, proposed in proposals %}\u00a4 {{ matiere }} :{% for user in proposed %}\r\n \u00a4 {{ user.get_full_name }}{% if user.profile.phone %}, {{ user.profile.phone }}{% endif %}{% if user.email %}, {{ user.email }}{% endif %}{% endfor %}\r\n\r\n{% endfor %}{% if unsatisfied %}Nous n'avons cependant pas pu trouver d'\u00e9l\u00e8ve disponible pour des cours de {% for matiere in unsatisfied %}{% if forloop.counter0 > 0 %}, {% endif %}{{ matiere }}{% endfor %}.\r\n\r\n{% endif %}Si pour une raison ou une autre ces num\u00e9ros ne suffisaient pas, n'h\u00e9sitez pas \u00e0 r\u00e9pondre \u00e0 cet e-mail et je vous en ferai parvenir d'autres sans probl\u00e8me.\r\n{% if extra|length > 0 %}\r\n{{ extra|safe }}\r\n{% endif %}\r\nCordialement,\r\n\r\n--\r\nLe COF, BdE de l'ENS" + } +}, +{ + "model": "custommail.custommail", + "pk": 12, + "fields": { + "shortname": "bda-attributions", + "subject": "R\u00e9sultats du tirage au sort", + "description": "Mail annon\u00e7ant les r\u00e9sultats du tirage au sort du BdA aux gagnants d'une ou plusieurs places", + "body": "Cher-e {{ member.first_name }},\r\n\r\nTu t'es inscrit-e pour le tirage au sort du BdA. Tu as \u00e9t\u00e9 s\u00e9lectionn\u00e9-e\r\npour les spectacles suivants :\r\n{% for place in places %}\r\n- 1 place pour {{ place }}{% endfor %}\r\n\r\n*Paiement*\r\nL'int\u00e9gralit\u00e9 de ces places de spectacles est \u00e0 r\u00e9gler d\u00e8s maintenant et AVANT\r\nvendredi prochain, au bureau du COF pendant les heures de permanences (du lundi au vendredi\r\nentre 12h et 14h, et entre 18h et 20h). Des facilit\u00e9s de paiement sont bien\r\n\u00e9videmment possibles : nous pouvons ne pas encaisser le ch\u00e8que imm\u00e9diatement,\r\nou bien d\u00e9couper votre paiement en deux fois. Pour ceux qui ne pourraient pas\r\nvenir payer au bureau, merci de nous contacter par mail.\r\n\r\n*Mode de retrait des places*\r\nAu moment du paiement, certaines places vous seront remises directement,\r\nd'autres seront \u00e0 r\u00e9cup\u00e9rer au cours de l'ann\u00e9e, d'autres encore seront\r\nnominatives et \u00e0 retirer le soir m\u00eame dans les the\u00e2tres correspondants.\r\nPour chaque spectacle, vous recevrez un mail quelques jours avant la\r\nrepr\u00e9sentation vous indiquant le mode de retrait.\r\n\r\nNous vous rappelons que l'obtention de places du BdA vous engage \u00e0\r\nrespecter les r\u00e8gles de fonctionnement :\r\nhttp://www.cof.ens.fr/bda/?page_id=1370\r\nUn syst\u00e8me de revente des places via les mails BdA-revente disponible\r\ndirectement sur votre compte GestioCOF.\r\n\r\nEn vous souhaitant de tr\u00e8s beaux spectacles tout au long de l'ann\u00e9e,\r\n--\r\nLe Bureau des Arts" + } +}, +{ + "model": "custommail.custommail", + "pk": 13, + "fields": { + "shortname": "bda-attributions-decus", + "subject": "R\u00e9sultats du tirage au sort", + "description": "Mail annon\u00e7ant les r\u00e9sultats du tirage au sort du BdA aux personnes n'ayant pas obtenu de place", + "body": "Cher-e {{ member.first_name }},\r\n\r\nTu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as\r\nobtenu aucune place.\r\n\r\nNous proposons cependant de nombreuses offres hors-tirage tout au long de\r\nl'ann\u00e9e, et nous t'invitons \u00e0 nous contacter si l'une d'entre elles\r\nt'int\u00e9resse !\r\n--\r\nLe Bureau des Arts" + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 1, + "fields": { + "name": "member", + "description": "Utilisateur de GestioCOF", + "custommail": 1, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 2, + "fields": { + "name": "member", + "description": "Utilisateur ayant eu une place pour ce spectacle", + "custommail": 2, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 3, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 2, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 4, + "fields": { + "name": "nb_attr", + "description": "Nombre de places obtenues", + "custommail": 2, + "typ": 2 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 5, + "fields": { + "name": "revente", + "description": "Revente mentionn\u00e9e dans le mail", + "custommail": 3, + "typ": 4 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 6, + "fields": { + "name": "member", + "description": "Personne int\u00e9ress\u00e9e par la place", + "custommail": 3, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 7, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 3, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 8, + "fields": { + "name": "site", + "description": "Site web (gestioCOF)", + "custommail": 3, + "typ": 5 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 9, + "fields": { + "name": "site", + "description": "Site web (gestioCOF)", + "custommail": 4, + "typ": 5 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 10, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 4, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 11, + "fields": { + "name": "member", + "description": "Personne int\u00e9ress\u00e9e par la place", + "custommail": 4, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 12, + "fields": { + "name": "acheteur", + "description": "Gagnant-e du tirage", + "custommail": 5, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 13, + "fields": { + "name": "vendeur", + "description": "Personne qui vend une place", + "custommail": 5, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 14, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 5, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 15, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 6, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 16, + "fields": { + "name": "vendeur", + "description": "Personne qui vend une place", + "custommail": 6, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 17, + "fields": { + "name": "acheteur", + "description": "Personne inscrite au tirage qui n'a pas eu la place", + "custommail": 6, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 18, + "fields": { + "name": "acheteur", + "description": "Gagnant-e du tirage", + "custommail": 7, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 19, + "fields": { + "name": "vendeur", + "description": "Personne qui vend une place", + "custommail": 7, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 20, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 7, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 21, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 8, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 22, + "fields": { + "name": "vendeur", + "description": "Personne qui vend la place", + "custommail": 8, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 23, + "fields": { + "name": "revente", + "description": "Revente mentionn\u00e9e dans le mail", + "custommail": 8, + "typ": 4 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 24, + "fields": { + "name": "vendeur", + "description": "Personne qui vend la place", + "custommail": 9, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 25, + "fields": { + "name": "show", + "description": "Spectacle", + "custommail": 9, + "typ": 3 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 26, + "fields": { + "name": "acheteur", + "description": "Personne qui prend la place au shotgun", + "custommail": 9, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 27, + "fields": { + "name": "demande", + "description": "Demande de petit cours", + "custommail": 10, + "typ": 6 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 28, + "fields": { + "name": "matieres", + "description": "Liste des mati\u00e8res concern\u00e9es par la demande", + "custommail": 10, + "typ": 7 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 29, + "fields": { + "name": "proposals", + "description": "Liste associant une liste d'enseignants \u00e0 chaque mati\u00e8re", + "custommail": 11, + "typ": 10 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 30, + "fields": { + "name": "unsatisfied", + "description": "Liste des mati\u00e8res pour lesquelles on n'a pas d'enseigant \u00e0 proposer", + "custommail": 11, + "typ": 7 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 31, + "fields": { + "name": "places", + "description": "Places de spectacle du participant", + "custommail": 12, + "typ": 11 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 32, + "fields": { + "name": "member", + "description": "Participant du tirage au sort", + "custommail": 12, + "typ": 1 + } +}, +{ + "model": "custommail.custommailvariable", + "pk": 33, + "fields": { + "name": "member", + "description": "Participant du tirage au sort", + "custommail": 13, + "typ": 1 + } +} +] diff --git a/gestioncof/migrations/0009_delete_custommail.py b/gestioncof/migrations/0009_delete_custommail.py new file mode 100644 index 00000000..60e374a3 --- /dev/null +++ b/gestioncof/migrations/0009_delete_custommail.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('gestioncof', '0008_py3'), + ] + + operations = [ + migrations.DeleteModel( + name='CustomMail', + ), + ] From 8bf2f715a46f37e18bed8fce728ad02f2b64caa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 23 Dec 2016 10:25:28 +0100 Subject: [PATCH 05/13] Correction de bugs et nettoyage --- bda/models.py | 39 +++++++++---------- bda/templates/{ => bda}/mails-rappel.html | 8 +++- bda/views.py | 4 +- gestioncof/petits_cours_views.py | 2 +- .../traitement_demande_petit_cours.html | 8 +++- 5 files changed, 34 insertions(+), 27 deletions(-) rename bda/templates/{ => bda}/mails-rappel.html (84%) diff --git a/bda/models.py b/bda/models.py index a14585ee..98ab622f 100644 --- a/bda/models.py +++ b/bda/models.py @@ -298,36 +298,35 @@ class SpectacleRevente(models.Model): # Envoie un mail au gagnant et au vendeur winner = random.choice(inscrits) self.soldTo = winner + datatuple = [] context = { 'acheteur': winner.user, 'vendeur': seller.user, 'show': spectacle, } - send_custom_mail( + datatuple.append(( 'bda-revente-winner', + context, + settings.MAIL_DATA['revente']['FROM'], [winner.user.email], - context=context, - from_email=settings.MAIL_DATA['revente']['FROM'] - ) - send_custom_mail( + )) + datatuple.append(( 'bda-revente-seller', - [seller.user.email], - context=context, - from_email=settings.MAIL_DATA['revente']['FROM'] - ) + context, + settings.MAIL_DATA['revente']['FROM'], + [seller.user.email] + )) # Envoie un mail aux perdants - datatuple = [( - 'bda-revente-loser', - { - 'acheteur': inscrit.user, - 'vendeur': seller.user, - 'show': spectacle - }, - settings.MAIL_DATA['revente']['FROM'], - [inscrit.user.email]) - for inscrit in inscrits if inscrit != winner - ] + for inscrit in inscrits: + if inscrit != winner: + context['acheteur'] = inscrit.user + datatuple.append(( + 'bda-revente-loser', + context, + settings.MAIL_DATA['revente']['FROM'], + [inscrit.user.email] + )) send_mass_custom_mail(datatuple) # Si personne ne veut de la place, elle part au shotgun else: diff --git a/bda/templates/mails-rappel.html b/bda/templates/bda/mails-rappel.html similarity index 84% rename from bda/templates/mails-rappel.html rename to bda/templates/bda/mails-rappel.html index 3fc15fa2..a2821e28 100644 --- a/bda/templates/mails-rappel.html +++ b/bda/templates/bda/mails-rappel.html @@ -28,8 +28,12 @@

Forme des mails


Une seule place

-
{{ exemple_mail_1place }}
+{% for part in exemple_mail_1place %} +
{{ part }}
+{% endfor %}
Deux places

-
{{ exemple_mail_2places }}
+{% for part in exemple_mail_2places %} +
{{ part }}
+{% endfor %} {% endblock %} diff --git a/bda/views.py b/bda/views.py index 4f0d717d..ad5fb490 100644 --- a/bda/views.py +++ b/bda/views.py @@ -466,7 +466,7 @@ def buy_revente(request, spectacle_id): } send_custom_mail( 'bda-buy-shotgun', - [revente.seller.user.email], + recipient_list=[revente.seller.user.email], context=context, from_email='bda@ens.fr' ) @@ -575,7 +575,7 @@ def send_rappel(request, spectacle_id): # Demande de confirmation else: ctxt['sent'] = False - return render(request, "mails-rappel.html", ctxt) + return render(request, "bda/mails-rappel.html", ctxt) def descriptions_spectacles(request, tirage_id): diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 973db315..18c715cf 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -155,7 +155,7 @@ def _generate_eleve_email(demande, proposed_for): render_custom_mail('petit-cours-mail-eleve', { "demande": demande, "matieres": matieres - })[1] + }) ) for user, matieres in proposed_for ] diff --git a/gestioncof/templates/traitement_demande_petit_cours.html b/gestioncof/templates/traitement_demande_petit_cours.html index d51f87b5..f533f0f1 100644 --- a/gestioncof/templates/traitement_demande_petit_cours.html +++ b/gestioncof/templates/traitement_demande_petit_cours.html @@ -30,10 +30,14 @@

Mails pour les membres proposés :

{% for proposeduser, mail in proposed_mails %}
Pour {{ proposeduser }}:
-
{{ mail }}
+ {% for part in mail %} +
{{ part }}
+ {% endfor %} {% endfor %}

Mail pour l'auteur de la demande :

-
{{ mainmail|safe }}
+ {% for part in mainmail %} +
{{ part|safe }}
+ {% endfor %} {% if redo %}{% endif %} From 74abd6c853eb5a9f0356e6a04b5d1d46cd147f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 23 Dec 2016 18:51:33 +0100 Subject: [PATCH 06/13] Fixe le comportement de syncmail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit syncmail ne devrait pas essayer de changer un email si un email du même shortname existe déjà. Ce n'était pas le cas auparavant --- gestioncof/management/commands/syncmails.py | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py index 6ce1fd6e..62936000 100644 --- a/gestioncof/management/commands/syncmails.py +++ b/gestioncof/management/commands/syncmails.py @@ -33,7 +33,6 @@ class Command(BaseCommand): status = {'synced': 0, 'unchanged': 0} for obj in mail_data: - model = obj['model'] fields = obj['fields'] # Pour les trois types d'objets : @@ -43,7 +42,7 @@ class Command(BaseCommand): # plus haut # Variable types - if model == 'custommail.variabletype': + if obj['model'] == 'custommail.variabletype': fields['inner1'] = assoc['types'].get(fields['inner1']) fields['inner2'] = assoc['types'].get(fields['inner2']) if fields['typ'] == 'model': @@ -55,21 +54,30 @@ class Command(BaseCommand): assoc['types'][obj['pk']] = var_type # Custom mails - if model == 'custommail.custommail': - mail, created = CustomMail.objects.get_or_create(**fields) - assoc['mails'][obj['pk']] = mail - if created: + if obj['model'] == 'custommail.custommail': + mail = None + try: + mail = CustomMail.objects.get( + shortname=fields['shortname']) + status['unchanged'] += 1 + except CustomMail.DoesNotExist: + mail = CustomMail.objects.create(**fields) + status['synced'] += 1 self.stdout.write( 'SYNCED {:s}'.format(fields['shortname'])) - status['synced'] += 1 - else: - status['unchanged'] += 1 + assoc['mails'][obj['pk']] = mail # Variables - if model == 'custommail.custommailvariable': + if obj['model'] == 'custommail.custommailvariable': fields['custommail'] = assoc['mails'].get(fields['custommail']) fields['typ'] = assoc['types'].get(fields['typ']) - CustomMailVariable.objects.get_or_create(**fields) + try: + CustomMailVariable.objects.get( + custommail=fields['custommail'], + name=fields['name'] + ) + except CustomMailVariable.DoesNotExist: + CustomMailVariable.objects.create(**fields) # C'est agréable d'avoir le résultat affiché self.stdout.write( From 9482ab441686e8cd106f4cfd97a7ee4f0df8e190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 23 Dec 2016 18:58:48 +0100 Subject: [PATCH 07/13] Update provisioning Il faut lancer `syncmails` au setup de GestioCOF --- provisioning/prepare_django.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/provisioning/prepare_django.sh b/provisioning/prepare_django.sh index c8c80d05..9cf584ee 100644 --- a/provisioning/prepare_django.sh +++ b/provisioning/prepare_django.sh @@ -3,5 +3,6 @@ source ~/venv/bin/activate python manage.py migrate +python manage.py syncmails python manage.py loaddata users root bda gestion sites python manage.py collectstatic --noinput From dd60c58bb8d75952073779f2c2c6cfd4db1782c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 24 Dec 2016 14:02:54 +0100 Subject: [PATCH 08/13] Follows the changes in custommail --- gestioncof/management/commands/syncmails.py | 14 ++-- gestioncof/management/data/custommail.json | 88 ++++++++++----------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py index 62936000..1d3dddb8 100644 --- a/gestioncof/management/commands/syncmails.py +++ b/gestioncof/management/commands/syncmails.py @@ -5,7 +5,7 @@ Import des mails de GestioCOF dans la base de donnée import json import os -from custommail.models import VariableType, CustomMail, CustomMailVariable +from custommail.models import Type, CustomMail, Variable from django.core.management.base import BaseCommand from django.contrib.contenttypes.models import ContentType @@ -45,12 +45,12 @@ class Command(BaseCommand): if obj['model'] == 'custommail.variabletype': fields['inner1'] = assoc['types'].get(fields['inner1']) fields['inner2'] = assoc['types'].get(fields['inner2']) - if fields['typ'] == 'model': + if fields['kind'] == 'model': fields['content_type'] = ( ContentType.objects .get_by_natural_key(*fields['content_type']) ) - var_type, _ = VariableType.objects.get_or_create(**fields) + var_type, _ = Type.objects.get_or_create(**fields) assoc['types'][obj['pk']] = var_type # Custom mails @@ -70,14 +70,14 @@ class Command(BaseCommand): # Variables if obj['model'] == 'custommail.custommailvariable': fields['custommail'] = assoc['mails'].get(fields['custommail']) - fields['typ'] = assoc['types'].get(fields['typ']) + fields['type'] = assoc['types'].get(fields['type']) try: - CustomMailVariable.objects.get( + Variable.objects.get( custommail=fields['custommail'], name=fields['name'] ) - except CustomMailVariable.DoesNotExist: - CustomMailVariable.objects.create(**fields) + except Variable.DoesNotExist: + Variable.objects.create(**fields) # C'est agréable d'avoir le résultat affiché self.stdout.write( diff --git a/gestioncof/management/data/custommail.json b/gestioncof/management/data/custommail.json index 0f81744c..9ee9b1ea 100644 --- a/gestioncof/management/data/custommail.json +++ b/gestioncof/management/data/custommail.json @@ -8,7 +8,7 @@ "user" ], "inner1": null, - "typ": "model", + "kind": "model", "inner2": null } }, @@ -18,7 +18,7 @@ "fields": { "content_type": null, "inner1": null, - "typ": "int", + "kind": "int", "inner2": null } }, @@ -31,7 +31,7 @@ "spectacle" ], "inner1": null, - "typ": "model", + "kind": "model", "inner2": null } }, @@ -44,7 +44,7 @@ "spectaclerevente" ], "inner1": null, - "typ": "model", + "kind": "model", "inner2": null } }, @@ -57,7 +57,7 @@ "site" ], "inner1": null, - "typ": "model", + "kind": "model", "inner2": null } }, @@ -70,7 +70,7 @@ "petitcoursdemande" ], "inner1": null, - "typ": "model", + "kind": "model", "inner2": null } }, @@ -80,7 +80,7 @@ "fields": { "content_type": null, "inner1": null, - "typ": "list", + "kind": "list", "inner2": null } }, @@ -90,7 +90,7 @@ "fields": { "content_type": null, "inner1": 1, - "typ": "list", + "kind": "list", "inner2": null } }, @@ -100,7 +100,7 @@ "fields": { "content_type": null, "inner1": null, - "typ": "pair", + "kind": "pair", "inner2": 8 } }, @@ -110,7 +110,7 @@ "fields": { "content_type": null, "inner1": 9, - "typ": "list", + "kind": "list", "inner2": null } }, @@ -120,7 +120,7 @@ "fields": { "content_type": null, "inner1": 3, - "typ": "list", + "kind": "list", "inner2": null } }, @@ -261,7 +261,7 @@ "name": "member", "description": "Utilisateur de GestioCOF", "custommail": 1, - "typ": 1 + "type": 1 } }, { @@ -271,7 +271,7 @@ "name": "member", "description": "Utilisateur ayant eu une place pour ce spectacle", "custommail": 2, - "typ": 1 + "type": 1 } }, { @@ -281,7 +281,7 @@ "name": "show", "description": "Spectacle", "custommail": 2, - "typ": 3 + "type": 3 } }, { @@ -291,7 +291,7 @@ "name": "nb_attr", "description": "Nombre de places obtenues", "custommail": 2, - "typ": 2 + "type": 2 } }, { @@ -301,7 +301,7 @@ "name": "revente", "description": "Revente mentionn\u00e9e dans le mail", "custommail": 3, - "typ": 4 + "type": 4 } }, { @@ -311,7 +311,7 @@ "name": "member", "description": "Personne int\u00e9ress\u00e9e par la place", "custommail": 3, - "typ": 1 + "type": 1 } }, { @@ -321,7 +321,7 @@ "name": "show", "description": "Spectacle", "custommail": 3, - "typ": 3 + "type": 3 } }, { @@ -331,7 +331,7 @@ "name": "site", "description": "Site web (gestioCOF)", "custommail": 3, - "typ": 5 + "type": 5 } }, { @@ -341,7 +341,7 @@ "name": "site", "description": "Site web (gestioCOF)", "custommail": 4, - "typ": 5 + "type": 5 } }, { @@ -351,7 +351,7 @@ "name": "show", "description": "Spectacle", "custommail": 4, - "typ": 3 + "type": 3 } }, { @@ -361,7 +361,7 @@ "name": "member", "description": "Personne int\u00e9ress\u00e9e par la place", "custommail": 4, - "typ": 1 + "type": 1 } }, { @@ -371,7 +371,7 @@ "name": "acheteur", "description": "Gagnant-e du tirage", "custommail": 5, - "typ": 1 + "type": 1 } }, { @@ -381,7 +381,7 @@ "name": "vendeur", "description": "Personne qui vend une place", "custommail": 5, - "typ": 1 + "type": 1 } }, { @@ -391,7 +391,7 @@ "name": "show", "description": "Spectacle", "custommail": 5, - "typ": 3 + "type": 3 } }, { @@ -401,7 +401,7 @@ "name": "show", "description": "Spectacle", "custommail": 6, - "typ": 3 + "type": 3 } }, { @@ -411,7 +411,7 @@ "name": "vendeur", "description": "Personne qui vend une place", "custommail": 6, - "typ": 1 + "type": 1 } }, { @@ -421,7 +421,7 @@ "name": "acheteur", "description": "Personne inscrite au tirage qui n'a pas eu la place", "custommail": 6, - "typ": 1 + "type": 1 } }, { @@ -431,7 +431,7 @@ "name": "acheteur", "description": "Gagnant-e du tirage", "custommail": 7, - "typ": 1 + "type": 1 } }, { @@ -441,7 +441,7 @@ "name": "vendeur", "description": "Personne qui vend une place", "custommail": 7, - "typ": 1 + "type": 1 } }, { @@ -451,7 +451,7 @@ "name": "show", "description": "Spectacle", "custommail": 7, - "typ": 3 + "type": 3 } }, { @@ -461,7 +461,7 @@ "name": "show", "description": "Spectacle", "custommail": 8, - "typ": 3 + "type": 3 } }, { @@ -471,7 +471,7 @@ "name": "vendeur", "description": "Personne qui vend la place", "custommail": 8, - "typ": 1 + "type": 1 } }, { @@ -481,7 +481,7 @@ "name": "revente", "description": "Revente mentionn\u00e9e dans le mail", "custommail": 8, - "typ": 4 + "type": 4 } }, { @@ -491,7 +491,7 @@ "name": "vendeur", "description": "Personne qui vend la place", "custommail": 9, - "typ": 1 + "type": 1 } }, { @@ -501,7 +501,7 @@ "name": "show", "description": "Spectacle", "custommail": 9, - "typ": 3 + "type": 3 } }, { @@ -511,7 +511,7 @@ "name": "acheteur", "description": "Personne qui prend la place au shotgun", "custommail": 9, - "typ": 1 + "type": 1 } }, { @@ -521,7 +521,7 @@ "name": "demande", "description": "Demande de petit cours", "custommail": 10, - "typ": 6 + "type": 6 } }, { @@ -531,7 +531,7 @@ "name": "matieres", "description": "Liste des mati\u00e8res concern\u00e9es par la demande", "custommail": 10, - "typ": 7 + "type": 7 } }, { @@ -541,7 +541,7 @@ "name": "proposals", "description": "Liste associant une liste d'enseignants \u00e0 chaque mati\u00e8re", "custommail": 11, - "typ": 10 + "type": 10 } }, { @@ -551,7 +551,7 @@ "name": "unsatisfied", "description": "Liste des mati\u00e8res pour lesquelles on n'a pas d'enseigant \u00e0 proposer", "custommail": 11, - "typ": 7 + "type": 7 } }, { @@ -561,7 +561,7 @@ "name": "places", "description": "Places de spectacle du participant", "custommail": 12, - "typ": 11 + "type": 11 } }, { @@ -571,7 +571,7 @@ "name": "member", "description": "Participant du tirage au sort", "custommail": 12, - "typ": 1 + "type": 1 } }, { @@ -581,7 +581,7 @@ "name": "member", "description": "Participant du tirage au sort", "custommail": 13, - "typ": 1 + "type": 1 } } ] From c72393d52158970bba69fceac39d9143181e2cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 24 Dec 2016 15:57:56 +0100 Subject: [PATCH 09/13] Update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index db2cc93b..002c1253 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,9 @@ Il ne vous reste plus qu'à initialiser les modèles de Django avec la commande python manage.py migrate +Charger les mails indispensables au bon fonctionnement de GestioCOF : + + python manage.py syncmails Une base de donnée pré-remplie est disponible en lançant la commande : From 0e759405c7c0593dc32709dab1d83bbf3b74b656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 11 Feb 2017 15:13:29 +0100 Subject: [PATCH 10/13] Change the migration index --- .../{0009_delete_custommail.py => 0010_delete_custommail.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename gestioncof/migrations/{0009_delete_custommail.py => 0010_delete_custommail.py} (82%) diff --git a/gestioncof/migrations/0009_delete_custommail.py b/gestioncof/migrations/0010_delete_custommail.py similarity index 82% rename from gestioncof/migrations/0009_delete_custommail.py rename to gestioncof/migrations/0010_delete_custommail.py index 60e374a3..63ebeca7 100644 --- a/gestioncof/migrations/0009_delete_custommail.py +++ b/gestioncof/migrations/0010_delete_custommail.py @@ -6,7 +6,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('gestioncof', '0008_py3'), + ('gestioncof', '0009_delete_clipper'), ] operations = [ From 62dc04c19ff272d6f11afe527374afffcf13333c Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 11 Feb 2017 15:33:22 +0100 Subject: [PATCH 11/13] cleaning ugly html --- bda/templates/bda/mails-rappel.html | 66 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/bda/templates/bda/mails-rappel.html b/bda/templates/bda/mails-rappel.html index a2821e28..73625d1c 100644 --- a/bda/templates/bda/mails-rappel.html +++ b/bda/templates/bda/mails-rappel.html @@ -1,39 +1,43 @@ {% extends "base_title.html" %} {% block realcontent %} -{% if sent %} -

Les mails de rappel pour le spectacle {{ show.title }} ont bien été envoyés aux personnes suivantes

-
    -{% for member in members %} -
  • {{ member.get_full_name }} ({{ member.email }})
  • -{% endfor %} -
-{% else %} -

Voulez vous envoyer les mails de rappel pour le spectacle - {{ show.title }} ?

- {% if show.rappel_sent %} -

Attention, les mails ont déjà été envoyés le - {{ show.rappel_sent }}

- {% endif %} -{% endif %} +

Mails de rappels

+ {% if sent %} +

Les mails de rappel pour le spectacle {{ show.title }} ont bien été envoyés aux personnes suivantes

+
    + {% for member in members %} +
  • {{ member.get_full_name }} ({{ member.email }})
  • + {% endfor %} +
+ {% else %} +

Voulez vous envoyer les mails de rappel pour le spectacle + {{ show.title }} ?

+ {% if show.rappel_sent %} +

Attention, les mails ont déjà été envoyés le + {{ show.rappel_sent }}

+ {% endif %} + {% endif %} -{% if not sent %} -
- {% csrf_token %} -
- -
-{% endif %} + {% if not sent %} +
+ {% csrf_token %} +
+ +
+
+ {% endif %} -

Forme des mails

+
+
+

Forme des mails

-
Une seule place

-{% for part in exemple_mail_1place %} -
{{ part }}
-{% endfor %} +

Une seule place

+ {% for part in exemple_mail_1place %} +
{{ part }}
+ {% endfor %} -
Deux places

-{% for part in exemple_mail_2places %} -
{{ part }}
-{% endfor %} +

Deux places

+ {% for part in exemple_mail_2places %} +
{{ part }}
+ {% endfor %} {% endblock %} From b4bf43744777e8babf6282774998573b759ecfc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 11 Feb 2017 16:15:17 +0100 Subject: [PATCH 12/13] Minor fixes --- bda/views.py | 6 +++--- gestioncof/views.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bda/views.py b/bda/views.py index 3097afe3..69f47da3 100644 --- a/bda/views.py +++ b/bda/views.py @@ -488,10 +488,10 @@ def buy_revente(request, spectacle_id): 'vendeur': revente.seller.user } send_custom_mail( - 'bda-buy-shotgun', - recipient_list=[revente.seller.user.email], + 'bda-buy-shotgun', + 'bda@ens.fr', + [revente.seller.user.email], context=context, - from_email='bda@ens.fr' ) return render(request, "bda-success.html", {"seller": revente.attribution.participant.user, diff --git a/gestioncof/views.py b/gestioncof/views.py index 9aaf18a3..aa021beb 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -435,9 +435,8 @@ def registration(request): profile = profile_form.save() if profile.is_cof and not was_cof: send_custom_mail( - "welcome", [member.email], + "welcome", "cof@ens.fr", [member.email], context={'member': member}, - from_email='cof@ens.fr' ) # Enregistrement des inscriptions aux événements for form in event_formset: From 924a289a78696382a32e0d886b863d5f61bd77fa Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 11 Feb 2017 16:21:13 +0100 Subject: [PATCH 13/13] cleaning UGLY django template style and moving some template files --- gestioncof/petits_cours_views.py | 8 +++++--- .../traitement_demande_petit_cours.html | 14 ++++++++------ ...raitement_demande_petit_cours_autre_niveau.html | 0 .../traitement_demande_petit_cours_success.html | 0 4 files changed, 13 insertions(+), 9 deletions(-) rename gestioncof/templates/{ => gestioncof}/traitement_demande_petit_cours.html (84%) rename gestioncof/templates/{ => gestioncof}/traitement_demande_petit_cours_autre_niveau.html (100%) rename gestioncof/templates/{ => gestioncof}/traitement_demande_petit_cours_success.html (100%) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 2db11bb9..a534e3a2 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -101,7 +101,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for, 'style="width:99%; height: 90px;">' '' }) - return render(request, "traitement_demande_petit_cours.html", + return render(request, "gestioncof/traitement_demande_petit_cours.html", {"demande": demande, "unsatisfied": unsatisfied, "proposals": proposals, @@ -211,7 +211,8 @@ def _traitement_other(request, demande, redo): unsatisfied.append(matiere) proposals = proposals.items() proposed_for = proposed_for.items() - return render(request, "traitement_demande_petit_cours_autre_niveau.html", + return render(request, + "gestiocof/traitement_demande_petit_cours_autre_niveau.html", {"demande": demande, "unsatisfied": unsatisfied, "proposals": proposals, @@ -277,7 +278,8 @@ def _traitement_post(request, demande): demande.traitee_par = request.user demande.processed = datetime.now() demande.save() - return render(request, "traitement_demande_petit_cours_success.html", + return render(request, + "gestioncof/traitement_demande_petit_cours_success.html", {"demande": demande, "redo": redo, }) diff --git a/gestioncof/templates/traitement_demande_petit_cours.html b/gestioncof/templates/gestioncof/traitement_demande_petit_cours.html similarity index 84% rename from gestioncof/templates/traitement_demande_petit_cours.html rename to gestioncof/templates/gestioncof/traitement_demande_petit_cours.html index f533f0f1..4be36a13 100644 --- a/gestioncof/templates/traitement_demande_petit_cours.html +++ b/gestioncof/templates/gestioncof/traitement_demande_petit_cours.html @@ -30,14 +30,16 @@

Mails pour les membres proposés :

{% for proposeduser, mail in proposed_mails %}
Pour {{ proposeduser }}:
- {% for part in mail %} -
{{ part }}
- {% endfor %} + {% with object=mail.0 content=mail.1 %} +
{{ object }}
+
{{ content }}
+ {% endwith %} {% endfor %}

Mail pour l'auteur de la demande :

- {% for part in mainmail %} -
{{ part|safe }}
- {% endfor %} + {% with object=mainmail.0 content=mainmail.1 %} +
{{ object }}
+
{{ content|safe }}
+ {% endwith %} {% if redo %}{% endif %} diff --git a/gestioncof/templates/traitement_demande_petit_cours_autre_niveau.html b/gestioncof/templates/gestioncof/traitement_demande_petit_cours_autre_niveau.html similarity index 100% rename from gestioncof/templates/traitement_demande_petit_cours_autre_niveau.html rename to gestioncof/templates/gestioncof/traitement_demande_petit_cours_autre_niveau.html diff --git a/gestioncof/templates/traitement_demande_petit_cours_success.html b/gestioncof/templates/gestioncof/traitement_demande_petit_cours_success.html similarity index 100% rename from gestioncof/templates/traitement_demande_petit_cours_success.html rename to gestioncof/templates/gestioncof/traitement_demande_petit_cours_success.html