diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py index 45b9c91a..4b90bc57 100644 --- a/bda/management/commands/manage_reventes.py +++ b/bda/management/commands/manage_reventes.py @@ -1,16 +1,21 @@ # -*- coding: utf-8 -*- +""" +Gestion en ligne de commande des reventes. +""" + from __future__ import unicode_literals +from datetime import timedelta from django.core.management import BaseCommand from django.utils import timezone -from datetime import timedelta from bda.models import SpectacleRevente class Command(BaseCommand): help = "Envoie les mails de notification et effectue " \ "les tirages au sort des reventes" + leave_locale_alone = True def handle(self, *args, **options): now = timezone.now() @@ -18,21 +23,21 @@ class Command(BaseCommand): for revente in reventes: # Check si < 24h if (revente.attribution.spectacle.date <= - revente.date + timedelta(days=1)) and \ - now >= revente.date + timedelta(minutes=15) and \ + revente.date + timedelta(days=1)) and \ + now >= revente.date + timedelta(minutes=15) and \ not revente.notif_sent: self.stdout.write(str(now)) revente.mail_shotgun() self.stdout.write("Mail de disponibilité immédiate envoyé") # Check si délai de retrait dépassé elif (now >= revente.date + timedelta(hours=1) and - not revente.notif_sent): + not revente.notif_sent): self.stdout.write(str(now)) revente.send_notif() self.stdout.write("Mail d'inscription à une revente envoyé") # Check si tirage à faire elif (now >= revente.expiration_time and - not revente.tirage_done): + not revente.tirage_done): self.stdout.write(str(now)) revente.tirage() self.stdout.write("Tirage effectué, mails envoyés") diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py index 1e8da240..88cf9d5c 100644 --- a/bda/management/commands/sendrappels.py +++ b/bda/management/commands/sendrappels.py @@ -1,16 +1,21 @@ # -*- coding: utf-8 -*- +""" +Gestion en ligne de commande des mails de rappel. +""" + from __future__ import unicode_literals +from datetime import timedelta from django.core.management.base import BaseCommand from django.utils import timezone -from datetime import timedelta from bda.models import Spectacle class Command(BaseCommand): help = 'Envoie les mails de rappel des spectacles dont la date ' \ 'approche.\nNe renvoie pas les mails déjà envoyés.' + leave_locale_alone = True def handle(self, *args, **options): now = timezone.now() diff --git a/bda/models.py b/bda/models.py index ccc49222..85c7fa4d 100644 --- a/bda/models.py +++ b/bda/models.py @@ -11,19 +11,13 @@ from datetime import timedelta from django.contrib.sites.models import Site from django.db import models from django.contrib.auth.models import User -from django.template import loader, Context +from django.template import loader from django.core import mail from django.conf import settings -from django.utils import timezone +from django.utils import timezone, formats from django.utils.encoding import python_2_unicode_compatible -def render_template(template_name, data): - tmpl = loader.get_template(template_name) - ctxt = Context(data) - return tmpl.render(ctxt) - - @python_2_unicode_compatible class Tirage(models.Model): title = models.CharField("Titre", max_length=300) @@ -34,12 +28,9 @@ class Tirage(models.Model): enable_do_tirage = models.BooleanField("Le tirage peut être lancé", default=False) - def date_no_seconds(self): - return self.fermeture.astimezone(timezone.get_current_timezone()) \ - .strftime('%d %b %Y %H:%M') - def __str__(self): - return "%s - %s" % (self.title, self.date_no_seconds()) + return "%s - %s" % (self.title, formats.localize( + timezone.template_localtime(self.fermeture))) @python_2_unicode_compatible @@ -89,15 +80,19 @@ class Spectacle(models.Model): def timestamp(self): return "%d" % calendar.timegm(self.date.utctimetuple()) - def date_no_seconds(self): - return self.date.astimezone(timezone.get_current_timezone()) \ - .strftime('%d %b %Y %H:%M') - def __str__(self): - return "%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), - self.location, self.price) + return "%s - %s, %s, %.02f€" % ( + self.title, + formats.localize(timezone.template_localtime(self.date)), + self.location, + self.price + ) def send_rappel(self): + """ + Envoie un mail de rappel à toutes les personnes qui ont une place pour + ce spectacle. + """ # On récupère la liste des participants members = {} for attr in Attribution.objects.filter(spectacle=self).all(): @@ -111,18 +106,17 @@ class Spectacle(models.Model): members[-1] = ['BdA', 2, 'bda@ens.fr'] # On écrit un mail personnalisé à chaque participant mails_to_send = [] - mail_object = "%s - %s - %s" % (self.title, self.date_no_seconds(), - self.location) + mail_object = str(self) for member in members.values(): - mail_body = render_template('mail-rappel.txt', { - 'name': member[0], - 'nb_attr': member[1], - 'show': self}) + 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']}) + 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() @@ -274,17 +268,17 @@ class SpectacleRevente(models.Model): mails_to_send = [] mail_object = "%s" % (self.attribution.spectacle) for participant in inscrits: - mail_body = render_template('mail-revente.txt', { - 'user': participant.user, - 'spectacle': self.attribution.spectacle, - 'revente': self, - 'domain': Site.objects.get_current().domain}) + 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']}) + 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() @@ -293,22 +287,26 @@ class SpectacleRevente(models.Model): self.save() def mail_shotgun(self): + """ + Envoie un mail à toutes les personnes intéréssées par le spectacle pour + 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 = render_template('mail-shotgun.txt', { - 'user': participant.user, - 'spectacle': self.attribution.spectacle, - 'domain': Site.objects.get_current(), - 'mail': self.attribution.participant.user.email}) + 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']}) + 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() @@ -317,6 +315,11 @@ class SpectacleRevente(models.Model): self.save() def tirage(self): + """ + Lance le tirage au sort associé à la revente. Un gagnant est choisi + parmis les personnes intéressées par le spectacle. Les personnes sont + ensuites prévenues par mail du résultat du tirage. + """ inscrits = list(self.answered_mail.all()) spectacle = self.attribution.spectacle seller = self.seller @@ -334,13 +337,17 @@ class SpectacleRevente(models.Model): 'spectacle': spectacle, } mails.append(mail.EmailMessage( - mail_subject, loader.render_to_string('mail-revente-winner.txt', context), + 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('mail-revente-seller.txt', context), + 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], @@ -351,11 +358,12 @@ class SpectacleRevente(models.Model): if inscrit == winner: continue - mail_body = loader.render_to_string('mail-revente-loser.txt', { - 'acheteur': inscrit.user, - 'vendeur': seller.user, - 'spectacle': spectacle, - }) + mail_body = loader.render_to_string( + 'bda/mails/revente-loser.txt', + {'acheteur': inscrit.user, + 'vendeur': seller.user, + 'spectacle': spectacle} + ) mails.append(mail.EmailMessage( mail_subject, mail_body, from_email=settings.MAIL_DATA['revente']['FROM'], diff --git a/bda/templates/bda-attrib.html b/bda/templates/bda-attrib.html index 5c705a79..5c22d2b3 100644 --- a/bda/templates/bda-attrib.html +++ b/bda/templates/bda-attrib.html @@ -22,7 +22,7 @@ {% for show, members, losers in results %}
-

{{ show.title }} - {{ show.date_no_seconds }} @ {{ show.location }}

+

{{ show.title }} - {{ show.date }} @ {{ show.location }}

{{ show.nrequests }} demandes pour {{ show.slots }} places {{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }}€ de déficit{% endif %} diff --git a/bda/templates/bda/mails/buy-shotgun.txt b/bda/templates/bda/mails/buy-shotgun.txt new file mode 100644 index 00000000..d7855143 --- /dev/null +++ b/bda/templates/bda/mails/buy-shotgun.txt @@ -0,0 +1,6 @@ +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/mail-rappel.txt b/bda/templates/bda/mails/rappel.txt similarity index 89% rename from bda/templates/mail-rappel.txt rename to bda/templates/bda/mails/rappel.txt index 4759a849..c6433f8a 100644 --- a/bda/templates/mail-rappel.txt +++ b/bda/templates/bda/mails/rappel.txt @@ -1,7 +1,7 @@ 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_no_seconds }} au {{ show.location }}. N'oublie pas de t'y rendre ! +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. diff --git a/bda/templates/mail-revente-loser.txt b/bda/templates/bda/mails/revente-loser.txt similarity index 100% rename from bda/templates/mail-revente-loser.txt rename to bda/templates/bda/mails/revente-loser.txt diff --git a/bda/templates/mail-revente-new.txt b/bda/templates/bda/mails/revente-new.txt similarity index 100% rename from bda/templates/mail-revente-new.txt rename to bda/templates/bda/mails/revente-new.txt diff --git a/bda/templates/mail-revente-seller.txt b/bda/templates/bda/mails/revente-seller.txt similarity index 100% rename from bda/templates/mail-revente-seller.txt rename to bda/templates/bda/mails/revente-seller.txt diff --git a/bda/templates/mail-revente-winner.txt b/bda/templates/bda/mails/revente-winner.txt similarity index 65% rename from bda/templates/mail-revente-winner.txt rename to bda/templates/bda/mails/revente-winner.txt index 8ca7236a..01ecfb86 100644 --- a/bda/templates/mail-revente-winner.txt +++ b/bda/templates/bda/mails/revente-winner.txt @@ -1,6 +1,6 @@ Bonjour {{ acheteur.first_name }}, -Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date_no_seconds }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. +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, diff --git a/bda/templates/mail-revente.txt b/bda/templates/bda/mails/revente.txt similarity index 95% rename from bda/templates/mail-revente.txt rename to bda/templates/bda/mails/revente.txt index 899afe3b..397a58d8 100644 --- a/bda/templates/mail-revente.txt +++ b/bda/templates/bda/mails/revente.txt @@ -1,6 +1,6 @@ Bonjour {{ user.first_name }} -Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date_no_seconds }}) +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 diff --git a/bda/templates/mail-shotgun.txt b/bda/templates/bda/mails/shotgun.txt similarity index 79% rename from bda/templates/mail-shotgun.txt rename to bda/templates/bda/mails/shotgun.txt index 899d5c85..69bc704c 100644 --- a/bda/templates/mail-shotgun.txt +++ b/bda/templates/bda/mails/shotgun.txt @@ -1,10 +1,10 @@ Bonjour {{ user.first_name }} -Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date_no_seconds }}) +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'addresse +cette place : elle est disponible immédiatement à l'adresse http://{{ domain }}{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous. Chaleureusement, diff --git a/bda/templates/etat-places.html b/bda/templates/etat-places.html index ebd15c38..4aa72ba1 100644 --- a/bda/templates/etat-places.html +++ b/bda/templates/etat-places.html @@ -18,7 +18,7 @@ {% for spectacle in spectacles %} {{ spectacle.title }} - {{ spectacle.date_no_seconds }} + {{ spectacle.date }} {{ spectacle.location }} {{ spectacle.slots }} places {{ spectacle.total }} demandes diff --git a/bda/templates/resume_places.html b/bda/templates/resume_places.html index 9ca5c78f..614a1656 100644 --- a/bda/templates/resume_places.html +++ b/bda/templates/resume_places.html @@ -11,7 +11,7 @@ {{place.spectacle.title}} {{place.spectacle.location}} - {{place.spectacle.date_no_seconds}} + {{place.spectacle.date}} {% if place.double %}deux places{%else%}une place{% endif %} {% endfor %} diff --git a/bda/templates/spectacle_list.html b/bda/templates/spectacle_list.html index 816461db..c7456f6e 100644 --- a/bda/templates/spectacle_list.html +++ b/bda/templates/spectacle_list.html @@ -19,7 +19,7 @@ {% for spectacle in object_list %} {{ spectacle.title }} - {{ spectacle.date_no_seconds }} + {{ spectacle.date }} {{ spectacle.location }} {{ spectacle.price |floatformat }}€ diff --git a/bda/views.py b/bda/views.py index 7d1f9be0..72fd5dd2 100644 --- a/bda/views.py +++ b/bda/views.py @@ -27,7 +27,7 @@ from datetime import timedelta from gestioncof.decorators import cof_required, buro_required from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\ - Tirage, render_template, SpectacleRevente + Tirage, SpectacleRevente from bda.algorithm import Algorithm from bda.forms import BaseBdaFormSet, TokenForm, ResellForm, AnnulForm,\ @@ -286,7 +286,7 @@ def revente(request, tirage_id): revente.seller = participant revente.date = timezone.now() mail_subject = "BdA-Revente : {:s}".format(attribution.spectacle.title) - mail_body = loader.render_to_string('mail-revente-new.txt', { + mail_body = loader.render_to_string('bda/mails/revente-new.txt', { 'vendeur': participant.user, 'spectacle': attribution.spectacle, 'revente': revente, @@ -453,14 +453,11 @@ def buy_revente(request, spectacle_id): revente = random.choice(reventes_shotgun) revente.soldTo = participant revente.save() - mail = """Bonjour ! - -Je souhaiterais racheter ta place pour %s le %s (%s) à %.02f€. -Contacte-moi si tu es toujours intéressé·e ! - -%s (%s)""" % (spectacle.title, spectacle.date_no_seconds(), - spectacle.location, spectacle.price, - request.user.get_full_name(), request.user.email) + mail = loader.render_to_string('bda/mails/buy-shotgun.txt', { + 'spectacle': spectacle, + 'acheteur': request.user, + 'vendeur': revente.seller.user, + }) send_mail("BdA-Revente : %s" % spectacle.title, mail, request.user.email, [revente.seller.user.email], @@ -553,11 +550,11 @@ def send_rappel(request, spectacle_id): # Mails d'exemples fake_member = request.user fake_member.nb_attr = 1 - exemple_mail_1place = render_template('mail-rappel.txt', { + exemple_mail_1place = loader.render_to_string('bda/mails/rappel.txt', { 'member': fake_member, 'show': show}) fake_member.nb_attr = 2 - exemple_mail_2places = render_template('mail-rappel.txt', { + exemple_mail_2places = loader.render_to_string('bda/mails/rappel.txt', { 'member': fake_member, 'show': show}) # Contexte diff --git a/cof/locale/__init__.py b/cof/locale/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cof/locale/fr/__init__.py b/cof/locale/fr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cof/locale/fr/formats.py b/cof/locale/fr/formats.py new file mode 100644 index 00000000..879d5ab8 --- /dev/null +++ b/cof/locale/fr/formats.py @@ -0,0 +1,9 @@ +# -*- encoding: utf-8 -*- + +""" +Formats français. +""" + +from __future__ import unicode_literals + +DATETIME_FORMAT = r'j F Y \à H:i' diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 419dd0eb..610ae549 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -200,3 +200,5 @@ def show_toolbar(request): DEBUG_TOOLBAR_CONFIG = { 'SHOW_TOOLBAR_CALLBACK': show_toolbar, } + +FORMAT_MODULE_PATH = 'cof.locale' diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index c3e43ea8..303cec2c 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -14,7 +14,7 @@ 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, Context +from django.template import loader from django.conf import settings from django.contrib.auth.decorators import login_required from django.db.models import Min @@ -33,12 +33,6 @@ import base64 import json -def render_template(template_path, data): - tmpl = loader.get_template(template_path) - context = Context(data) - return tmpl.render(context) - - class DemandeListView(ListView): model = PetitCoursDemande template_name = "petits_cours_demandes_list.html" @@ -137,14 +131,14 @@ 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_template("petits-cours-mail-demandeur.txt", - {"proposals": proposals, - "unsatisfied": unsatisfied, - "extra": - '' - }) + mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", { + "proposals": proposals, + "unsatisfied": unsatisfied, + "extra": + '' + }) return render(request, "traitement_demande_petit_cours.html", {"demande": demande, "unsatisfied": unsatisfied, @@ -163,8 +157,10 @@ def _finalize_traitement(request, demande, proposals, proposed_for, def _generate_eleve_email(demande, proposed_for): proposed_mails = [] for user, matieres in proposed_for: - msg = render_template("petits-cours-mail-eleve.txt", - {"demande": demande, "matieres": matieres}) + msg = loader.render_to_string("petits-cours-mail-eleve.txt", { + "demande": demande, + "matieres": matieres + }) proposed_mails.append((user, msg)) return proposed_mails @@ -278,10 +274,11 @@ def _traitement_post(request, demande): proposals_list = proposals.items() proposed_for = proposed_for.items() proposed_mails = _generate_eleve_email(demande, proposed_for) - mainmail = render_template("petits-cours-mail-demandeur.txt", - {"proposals": proposals_list, - "unsatisfied": unsatisfied, - "extra": extra}) + mainmail = loader.render_to_string("petits-cours-mail-demandeur.txt", { + "proposals": proposals_list, + "unsatisfied": unsatisfied, + "extra": extra, + }) frommail = settings.MAIL_DATA['petits_cours']['FROM'] bccaddress = settings.MAIL_DATA['petits_cours']['BCC'] replyto = settings.MAIL_DATA['petits_cours']['REPLYTO']