From ce03a28b4be3ae2d2b4e7f40d5ef5756f3179425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 12 Jul 2016 20:35:42 +0200 Subject: [PATCH 01/12] Ajoute une commande pour les mails de rappel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les mails de rappel pour les spectacles à venir (dans les 4 jours) peuvent être envoyés à l'aide de la commande `python manage.py sendrappels` Il suffit donc de mettre un cron qui lance cette commande à un intervalle régulier pour ne plus avoir à se soucier des mails de rappel. Fixes #1 --- bda/management/__init__.py | 0 bda/management/commands/__init__.py | 0 bda/management/commands/sendrappels.py | 30 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 bda/management/__init__.py create mode 100644 bda/management/commands/__init__.py create mode 100644 bda/management/commands/sendrappels.py diff --git a/bda/management/__init__.py b/bda/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bda/management/commands/__init__.py b/bda/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py new file mode 100644 index 00000000..e66b0b23 --- /dev/null +++ b/bda/management/commands/sendrappels.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +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.' + + def handle(self, *args, **options): + now = timezone.now() + delay = timedelta(4) + shows = Spectacle.objects \ + .filter(date__range=(now, now+delay)) \ + .filter(tirage__active=True) \ + .filter(rappel_sent__isnull=True) \ + .all() + for show in shows: + show.send_rappel() + show.rappel_sent = now + show.save() + self.stdout.write( + 'Mails de rappels pour %s envoyés avec succès.' % show) + if not shows: + self.stdout.write('Aucun mail à envoyer.') From 21b8b6042f6d99f96365b8931cf2f4347a090f38 Mon Sep 17 00:00:00 2001 From: Basile Clement Date: Thu, 26 May 2016 22:44:10 +0200 Subject: [PATCH 02/12] =?UTF-8?q?Compatibilit=C3=A9=20python=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rend GestioCOF compatible avec python 3. En particulier, il s'agit de : - Utiliser la version "fonction" de `print` dans `sync_clipper` et `tirage_bda`, avec le `from __future__ import print_function` pour garder la compatibilité avec python 2 - Utiliser de l'unicode par défaut, même en python 2, avec `from __future__ import unicode_literals` et le décorateur de compatibilité `python_2_unicode_compatible` de Django pour les modèles, comme décrit à https://docs.djangoproject.com/en/1.9/topics/python3/#str-and-unicode-methods - Utiliser `six.text_type` à la place de `unicode` Fixes #2. --- bda/admin.py | 18 +++--- bda/algorithm.py | 1 + bda/autocomplete_light_registry.py | 2 + bda/models.py | 27 +++++--- bda/views.py | 7 ++- cof/urls.py | 2 + gestioncof/admin.py | 13 +++- gestioncof/autocomplete.py | 2 + gestioncof/autocomplete_light_registry.py | 2 + gestioncof/csv_views.py | 2 + gestioncof/decorators.py | 2 + gestioncof/models.py | 77 +++++++++++++---------- gestioncof/petits_cours_models.py | 39 +++++++----- gestioncof/petits_cours_views.py | 6 +- gestioncof/templatetags/utils.py | 6 +- gestioncof/views.py | 32 ++++++++++ gestioncof/widgets.py | 4 +- sync_clipper.py | 13 ++-- 18 files changed, 174 insertions(+), 81 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index d989295d..cc4746ca 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + from django.core.mail import send_mail from django.contrib import admin @@ -52,9 +54,9 @@ class ParticipantAdmin(admin.ModelAdmin): def total(self, obj): tot = obj.total if tot: - return u"%.02f €" % tot + return "%.02f €" % tot else: - return u"0 €" + return "0 €" total.admin_order_field = "total" total.short_description = "Total à payer" list_display = ("user", "nb_places", "total", "paid", "paymenttype", @@ -70,7 +72,7 @@ class ParticipantAdmin(admin.ModelAdmin): for member in queryset.all(): attribs = member.attributions.all() if len(attribs) == 0: - mail = u"""Cher-e %s, + mail = """Cher-e %s, Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as obtenu aucune place. @@ -120,7 +122,7 @@ Le Bureau des Arts attribs_text = "" name = member.user.get_full_name() for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib + 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')) @@ -129,14 +131,14 @@ Le Bureau des Arts fail_silently=True) count = len(queryset.all()) if count == 1: - message_bit = u"1 membre a" + message_bit = "1 membre a" plural = "" else: - message_bit = u"%d membres ont" % count + message_bit = "%d membres ont" % count plural = "s" - self.message_user(request, u"%s été informé%s avec succès." + self.message_user(request, "%s été informé%s avec succès." % (message_bit, plural)) - send_attribs.short_description = u"Envoyer les résultats par mail" + send_attribs.short_description = "Envoyer les résultats par mail" class AttributionAdminForm(forms.ModelForm): diff --git a/bda/algorithm.py b/bda/algorithm.py index 005e714f..4a2dbdcc 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -1,6 +1,7 @@ # coding: utf-8 from __future__ import division +from __future__ import unicode_literals from django.db.models import Max diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py index 7aa43b07..aa6d4d57 100644 --- a/bda/autocomplete_light_registry.py +++ b/bda/autocomplete_light_registry.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import autocomplete_light from bda.models import Participant, Spectacle diff --git a/bda/models.py b/bda/models.py index 349a71e4..d7d64db0 100644 --- a/bda/models.py +++ b/bda/models.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + import calendar from django.db import models @@ -8,6 +10,7 @@ from django.template import loader, Context from django.core import mail from django.conf import settings from django.utils import timezone +from django.utils.encoding import python_2_unicode_compatible def render_template(template_name, data): @@ -16,6 +19,7 @@ def render_template(template_name, data): return tmpl.render(ctxt) +@python_2_unicode_compatible class Tirage(models.Model): title = models.CharField("Titre", max_length=300) ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") @@ -26,18 +30,20 @@ class Tirage(models.Model): def date_no_seconds(self): return self.fermeture.strftime('%d %b %Y %H:%M') - def __unicode__(self): - return u"%s - %s" % (self.title, self.date_no_seconds()) + def __str__(self): + return "%s - %s" % (self.title, self.date_no_seconds()) +@python_2_unicode_compatible class Salle(models.Model): name = models.CharField("Nom", max_length=300) address = models.TextField("Adresse") - def __unicode__(self): + def __str__(self): return self.name +@python_2_unicode_compatible class Spectacle(models.Model): title = models.CharField("Titre", max_length=300) date = models.DateTimeField("Date & heure") @@ -57,7 +63,7 @@ class Spectacle(models.Model): ordering = ("priority", "date", "title",) def __repr__(self): - return u"[%s]" % self.__unicode__() + return "[%s]" % self def timestamp(self): return "%d" % calendar.timegm(self.date.utctimetuple()) @@ -65,9 +71,9 @@ class Spectacle(models.Model): def date_no_seconds(self): return self.date.strftime('%d %b %Y %H:%M') - def __unicode__(self): - return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), - self.location, self.price) + def __str__(self): + return "%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), + self.location, self.price) def send_rappel(self): # On récupère la liste des participants @@ -156,10 +162,11 @@ class ChoixSpectacle(models.Model): verbose_name_plural = "voeux" +@python2_unicode_compatible class Attribution(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="attribues") - given = models.BooleanField(u"Donnée", default=False) + given = models.BooleanField("Donnée", default=False) - def __unicode__(self): - return u"%s -- %s" % (self.participant, self.spectacle) + def __str__(self): + return "%s -- %s" % (self.participant, self.spectacle) diff --git a/bda/views.py b/bda/views.py index 844ef60c..1ca76a5a 100644 --- a/bda/views.py +++ b/bda/views.py @@ -1,6 +1,7 @@ # coding: utf-8 from __future__ import division +from __future__ import unicode_literals from django.shortcuts import render, get_object_or_404 from django.contrib.auth.decorators import login_required @@ -145,7 +146,7 @@ def inscription(request, tirage_id): return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": - u"Tirage au sort dans la journée !", + "Tirage au sort dans la journée !", "choices": choices}) def formfield_callback(f, **kwargs): @@ -223,7 +224,7 @@ def do_tirage(request, tirage_id): deficit = (show.slots - len(members)) * show.price total_sold += show.slots * show.price if deficit >= 0: - if u"Opéra" in show.location.name: + if "Opéra" in show.location.name: opera_deficit += deficit total_deficit += deficit data["total_sold"] = total_sold - total_deficit @@ -277,7 +278,7 @@ def do_resell(request, form): spectacle = form.cleaned_data["spectacle"] count = form.cleaned_data["count"] places = "2 places" if count == "2" else "une place" - mail = u"""Bonjour, + mail = """Bonjour, Je souhaite revendre %s pour %s le %s (%s) à %.02f€. Contactez moi par email si vous êtes intéressé·e·s ! diff --git a/cof/urls.py b/cof/urls.py index b5d2b65a..16c6a5f6 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -1,5 +1,7 @@ # -*-coding:utf-8 -* +from __future__ import unicode_literals + from django.conf import settings from django.conf.urls import patterns, include, url from django.conf.urls.static import static diff --git a/gestioncof/admin.py b/gestioncof/admin.py index 8a1fb431..1c9ea5ca 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + from django.contrib import admin from gestioncof.models import * from gestioncof.petits_cours_models import * @@ -8,6 +10,7 @@ from django.contrib.auth.admin import UserAdmin from django.core.urlresolvers import reverse from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +import django.utils.six as six import autocomplete_light @@ -168,17 +171,21 @@ class UserProfileAdmin(UserAdmin): ] +# FIXME: This is absolutely horrible. def user_unicode(self): if self.first_name and self.last_name: - return u"%s %s (%s)" % (self.first_name, self.last_name, self.username) + return "%s %s (%s)" % (self.first_name, self.last_name, self.username) else: return self.username -User.__unicode__ = user_unicode +if six.PY2: + User.__unicode__ = user_unicode +else: + User.__str__ = user_unicode class EventRegistrationAdmin(admin.ModelAdmin): form = autocomplete_light.modelform_factory(EventRegistration, exclude=[]) - list_display = ('__unicode__', 'event', 'user', 'paid') + list_display = ('__unicode__' if six.PY2 else '__str__', 'event', 'user', 'paid') list_filter = ('paid',) search_fields = ('user__username', 'user__first_name', 'user__last_name', 'user__email', 'event__title') diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 21b5c3bc..248a6ae7 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django import shortcuts from django.http import Http404 from django.db.models import Q diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index 4a2737cb..1b211691 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import autocomplete_light from django.contrib.auth.models import User diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py index 733768dc..f8037413 100644 --- a/gestioncof/csv_views.py +++ b/gestioncof/csv_views.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import csv from django.http import HttpResponse, HttpResponseForbidden from django.template.defaultfilters import slugify diff --git a/gestioncof/decorators.py b/gestioncof/decorators.py index 62c527df..e5416e32 100644 --- a/gestioncof/decorators.py +++ b/gestioncof/decorators.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django_cas_ng.decorators import user_passes_test diff --git a/gestioncof/models.py b/gestioncof/models.py index 540145d5..ccb85bad 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -1,32 +1,36 @@ # coding: utf-8 +from __future__ import unicode_literals + from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ +from django.utils.encoding import python_2_unicode_compatible +import django.utils.six as six from django.db.models.signals import post_save -from petits_cours_models import * +from gestioncof.petits_cours_models import * OCCUPATION_CHOICES = ( - ('exterieur', _(u"Extérieur")), - ('1A', _(u"1A")), - ('2A', _(u"2A")), - ('3A', _(u"3A")), - ('4A', _(u"4A")), - ('archicube', _(u"Archicube")), - ('doctorant', _(u"Doctorant")), - ('CST', _(u"CST")), + ('exterieur', _("Extérieur")), + ('1A', _("1A")), + ('2A', _("2A")), + ('3A', _("3A")), + ('4A', _("4A")), + ('archicube', _("Archicube")), + ('doctorant', _("Doctorant")), + ('CST', _("CST")), ) TYPE_COTIZ_CHOICES = ( - ('etudiant', _(u"Normalien étudiant")), - ('normalien', _(u"Normalien élève")), - ('exterieur', _(u"Extérieur")), + ('etudiant', _("Normalien étudiant")), + ('normalien', _("Normalien élève")), + ('exterieur', _("Extérieur")), ) TYPE_COMMENT_FIELD = ( - ('text', _(u"Texte long")), - ('char', _(u"Texte court")), + ('text', _("Texte long")), + ('char', _("Texte court")), ) @@ -69,8 +73,8 @@ class CofProfile(models.Model): verbose_name = "Profil COF" verbose_name_plural = "Profils COF" - def __unicode__(self): - return unicode(self.user.username) + def __str__(self): + return six.text_type(self.user.username) def create_user_profile(sender, instance, created, **kwargs): @@ -86,6 +90,7 @@ class Club(models.Model): membres = models.ManyToManyField(User, related_name="clubs") +@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) @@ -97,10 +102,11 @@ class CustomMail(models.Model): verbose_name = "Mail personnalisable" verbose_name_plural = "Mails personnalisables" - def __unicode__(self): - return u"%s: %s" % (self.shortname, self.title) + 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) location = models.CharField("Lieu", max_length=200) @@ -116,10 +122,11 @@ class Event(models.Model): class Meta: verbose_name = "Événement" - def __unicode__(self): - return unicode(self.title) + def __str__(self): + return six.text_type(self.title) +@python_2_unicode_compatible class EventCommentField(models.Model): event = models.ForeignKey(Event, related_name="commentfields") name = models.CharField("Champ", max_length=200) @@ -130,8 +137,8 @@ class EventCommentField(models.Model): class Meta: verbose_name = "Champ" - def __unicode__(self): - return unicode(self.name) + def __str__(self): + return six.text_type(self.name) class EventCommentValue(models.Model): @@ -141,6 +148,7 @@ class EventCommentValue(models.Model): content = models.TextField("Contenu", blank=True, null=True) +@python_2_unicode_compatible class EventOption(models.Model): event = models.ForeignKey(Event, related_name="options") name = models.CharField("Option", max_length=200) @@ -149,10 +157,11 @@ class EventOption(models.Model): class Meta: verbose_name = "Option" - def __unicode__(self): - return unicode(self.name) + def __str__(self): + return six.text_type(self.name) +@python_2_unicode_compatible class EventOptionChoice(models.Model): event_option = models.ForeignKey(EventOption, related_name="choices") value = models.CharField("Valeur", max_length=200) @@ -161,10 +170,11 @@ class EventOptionChoice(models.Model): verbose_name = "Choix" verbose_name_plural = "Choix" - def __unicode__(self): - return unicode(self.value) + def __str__(self): + return six.text_type(self.value) +@python_2_unicode_compatible class EventRegistration(models.Model): user = models.ForeignKey(User) event = models.ForeignKey(Event) @@ -182,6 +192,7 @@ class EventRegistration(models.Model): unicode(self.event.title)) +@python_2_unicode_compatible class Survey(models.Model): title = models.CharField("Titre", max_length=200) details = models.TextField("Détails", blank=True) @@ -191,10 +202,11 @@ class Survey(models.Model): class Meta: verbose_name = "Sondage" - def __unicode__(self): - return unicode(self.title) + def __str__(self): + return six.text_type(self.title) +@python_2_unicode_compatible class SurveyQuestion(models.Model): survey = models.ForeignKey(Survey, related_name="questions") question = models.CharField("Question", max_length=200) @@ -203,10 +215,11 @@ class SurveyQuestion(models.Model): class Meta: verbose_name = "Question" - def __unicode__(self): - return unicode(self.question) + def __str__(self): + return six.text_type(self.question) +@python_2_unicode_compatible class SurveyQuestionAnswer(models.Model): survey_question = models.ForeignKey(SurveyQuestion, related_name="answers") answer = models.CharField("Réponse", max_length=200) @@ -214,8 +227,8 @@ class SurveyQuestionAnswer(models.Model): class Meta: verbose_name = "Réponse" - def __unicode__(self): - return unicode(self.answer) + def __str__(self): + return six.text_type(self.answer) class SurveyAnswer(models.Model): diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index a9aede0c..b8487478 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -1,25 +1,30 @@ # coding: utf-8 +from __future__ import unicode_literals + from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ +from django.utils.encoding import python_2_unicode_compatible +from django.utils.six.moves import reduce def choices_length(choices): return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0) LEVELS_CHOICES = ( - ('college', _(u"Collège")), - ('lycee', _(u"Lycée")), - ('prepa1styear', _(u"Prépa 1ère année / L1")), - ('prepa2ndyear', _(u"Prépa 2ème année / L2")), - ('licence3', _(u"Licence 3")), - ('other', _(u"Autre (préciser dans les commentaires)")), + ('college', _("Collège")), + ('lycee', _("Lycée")), + ('prepa1styear', _("Prépa 1ère année / L1")), + ('prepa2ndyear', _("Prépa 2ème année / L2")), + ('licence3', _("Licence 3")), + ('other', _("Autre (préciser dans les commentaires)")), ) +@python_2_unicode_compatible class PetitCoursSubject(models.Model): - name = models.CharField(_(u"Matière"), max_length=30) + name = models.CharField(_("Matière"), max_length=30) users = models.ManyToManyField(User, related_name="petits_cours_matieres", through="PetitCoursAbility") @@ -27,10 +32,11 @@ class PetitCoursSubject(models.Model): verbose_name = "Matière de petits cours" verbose_name_plural = "Matières des petits cours" - def __unicode__(self): + def __str__(self): return self.name +@python_2_unicode_compatible class PetitCoursAbility(models.Model): user = models.ForeignKey(User) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière")) @@ -43,11 +49,12 @@ class PetitCoursAbility(models.Model): verbose_name = "Compétence petits cours" verbose_name_plural = "Compétences des petits cours" - def __unicode__(self): - return u"%s - %s - %s" % (self.user.username, + def __str__(self): + return "%s - %s - %s" % (self.user.username, self.matiere, self.niveau) +@python_2_unicode_compatible class PetitCoursDemande(models.Model): name = models.CharField(_(u"Nom/prénom"), max_length=200) email = models.CharField(_(u"Adresse email"), max_length=300) @@ -89,11 +96,12 @@ class PetitCoursDemande(models.Model): verbose_name = "Demande de petits cours" verbose_name_plural = "Demandes de petits cours" - def __unicode__(self): - return u"Demande %d du %s" % (self.id, - self.created.strftime("%d %b %Y")) + def __str__(self): + return "Demande %d du %s" % (self.id, + self.created.strftime("%d %b %Y")) +@python_2_unicode_compatible class PetitCoursAttribution(models.Model): user = models.ForeignKey(User) demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande")) @@ -107,11 +115,12 @@ class PetitCoursAttribution(models.Model): verbose_name = "Attribution de petits cours" verbose_name_plural = "Attributions de petits cours" - def __unicode__(self): + def __str__(self): return u"Attribution de la demande %d à %s pour %s" \ % (self.demande.id, self.user.username, self.matiere) +@python_2_unicode_compatible class PetitCoursAttributionCounter(models.Model): user = models.ForeignKey(User) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere")) @@ -122,5 +131,5 @@ class PetitCoursAttributionCounter(models.Model): verbose_name_plural = "Compteurs d'attributions de petits cours" def __unicode__(self): - return u"%d demandes envoyées à %s pour %s" \ + return "%d demandes envoyées à %s pour %s" \ % (self.count, self.user.username, self.matiere) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 2e8c420a..7cba7ae1 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + from django.shortcuts import render, get_object_or_404, redirect from django.core import mail from django.core.mail import EmailMessage @@ -196,9 +198,9 @@ def _traitement_other_preparing(request, demande): else: proposed_for[user].append(matiere) if not proposals[matiere]: - errors.append(u"Aucune proposition pour %s" % (matiere,)) + errors.append("Aucune proposition pour %s" % (matiere,)) elif len(proposals[matiere]) < 3: - errors.append(u"Seulement %d proposition%s pour %s" + errors.append("Seulement %d proposition%s pour %s" % (len(proposals[matiere]), "s" if len(proposals[matiere]) > 1 else "", matiere)) diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 5847f9a6..4785c822 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django import template from django.utils.safestring import mark_safe @@ -22,7 +24,7 @@ def highlight_text(text, q): @register.filter def highlight_user(user, q): if user.first_name and user.last_name: - text = u"%s %s (%s)" % (user.first_name, user.last_name, user.username) + text = "%s %s (%s)" % (user.first_name, user.last_name, user.username) else: text = user.username return highlight_text(text, q) @@ -30,7 +32,7 @@ def highlight_user(user, q): @register.filter def highlight_clipper(clipper, q): if clipper.fullname: - text = u"%s (%s)" % (clipper.fullname, clipper.username) + text = "%s (%s)" % (clipper.fullname, clipper.username) else: text = clipper.username return highlight_text(text, q) diff --git a/gestioncof/views.py b/gestioncof/views.py index 11d15d53..dc05d816 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + import unicodecsv from django.shortcuts import redirect, get_object_or_404, render @@ -7,6 +9,7 @@ from django.http import Http404, HttpResponse from django.contrib.auth.decorators import login_required from django.contrib.auth.views import login as django_login_view from django.contrib.auth.models import User +import django.utils.six as six from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \ SurveyQuestionAnswer @@ -277,6 +280,35 @@ def survey_status(request, survey_id): "form": form}) +class UserProfileForm(forms.ModelForm): + first_name = forms.CharField(label=_('Prénom'), max_length=30) + last_name = forms.CharField(label=_('Nom'), max_length=30) + + def __init__(self, *args, **kw): + super(UserProfileForm, self).__init__(*args, **kw) + self.fields['first_name'].initial = self.instance.user.first_name + self.fields['last_name'].initial = self.instance.user.last_name + + self.fields.keyOrder = [ + 'first_name', + 'last_name', + 'phone', + 'mailing_cof', + 'mailing_bda', + 'mailing_bda_revente', + ] + + def save(self, *args, **kw): + super(UserProfileForm, self).save(*args, **kw) + self.instance.user.first_name = self.cleaned_data.get('first_name') + self.instance.user.last_name = self.cleaned_data.get('last_name') + self.instance.user.save() + + class Meta: + model = CofProfile + fields = ("phone", "mailing_cof", "mailing_bda", "mailing_bda_revente",) +>>>>>>> Compatibilité python 3 + @login_required def profile(request): success = False diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index 0f36f202..d819f5a2 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + from django.forms.widgets import Widget from django.forms.utils import flatatt from django.utils.safestring import mark_safe @@ -15,5 +17,5 @@ class TriStateCheckbox(Widget): if value is None: value = 'none' final_attrs = self.build_attrs(attrs, value=value) - output = [u"" % flatatt(final_attrs)] + output = ["" % flatatt(final_attrs)] return mark_safe('\n'.join(output)) diff --git a/sync_clipper.py b/sync_clipper.py index 4dac6447..78a88e76 100644 --- a/sync_clipper.py +++ b/sync_clipper.py @@ -1,4 +1,7 @@ #!/usr/bin/env python + +from __future__ import print_function, unicode_literals + import os import sys @@ -7,10 +10,10 @@ if __name__ == "__main__": from gestioncof.models import Clipper current = {} - print "[ FETCHING ]" + print("[ FETCHING ]") for clipper in Clipper.objects.all(): current[clipper.username] = clipper - print "[ SYNCING ]" + print("[ SYNCING ]") for line in sys.stdin: bits = line.split(":") username = bits[0] @@ -20,9 +23,9 @@ if __name__ == "__main__": if clipper.fullname != fullname: clipper.fullname = fullname clipper.save() - print "Updated", username + print("Updated", username) else: clipper = Clipper(username=username, fullname=fullname) clipper.save() - print "Created", username - print "[ DONE ]" + print("Created", username) + print("[ DONE ]") From b3c45afb49eab9026f61076a54991cee4a08a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 8 Jul 2016 23:04:34 +0200 Subject: [PATCH 03/12] =?UTF-8?q?Passage=20=C3=A0=20python=203=20-=20strin?= =?UTF-8?q?gs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/forms.py | 4 +++- gestioncof/admin.py | 2 +- gestioncof/forms.py | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 213ec17b..9c73ff5f 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + from django import forms from django.forms.models import BaseInlineFormSet from bda.models import Spectacle @@ -33,7 +35,7 @@ class TokenForm(forms.Form): class SpectacleModelChoiceField(forms.ModelChoiceField): def label_from_instance(self, obj): - return u"%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), + return "%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), obj.location, obj.price) diff --git a/gestioncof/admin.py b/gestioncof/admin.py index 1c9ea5ca..fb188f4b 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -213,7 +213,7 @@ class PetitCoursAttributionCounterAdmin(admin.ModelAdmin): def reset(self, request, queryset): queryset.update(count=0) - reset.short_description = u"Remise à zéro du compteur" + reset.short_description = "Remise à zéro du compteur" class PetitCoursDemandeAdmin(admin.ModelAdmin): diff --git a/gestioncof/forms.py b/gestioncof/forms.py index bf983df5..7479586e 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import unicode_literals + from django import forms from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User @@ -169,8 +171,8 @@ class EventStatusFilterForm(forms.Form): class UserProfileForm(forms.ModelForm): - first_name = forms.CharField(label=_(u'Prénom'), max_length=30) - last_name = forms.CharField(label=_(u'Nom'), max_length=30) + first_name = forms.CharField(label=_('Prénom'), max_length=30) + last_name = forms.CharField(label=_('Nom'), max_length=30) def __init__(self, *args, **kw): super(UserProfileForm, self).__init__(*args, **kw) From e26eee539b5aab6bac28a952677f900b602f409c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 9 Jul 2016 00:17:20 +0200 Subject: [PATCH 04/12] =?UTF-8?q?Ajoute=20py3=20=C3=A0a=20la=20config=20de?= =?UTF-8?q?=20la=20VM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- provisioning/bootstrap.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index dde6e24a..ce3ef1e7 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -8,7 +8,7 @@ DBNAME="cof_gestion" DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" # Installation de paquets utiles -apt-get update && apt-get install -y mercurial python-pip python-dev libmysqlclient-dev +apt-get update && apt-get install -y mercurial python3-pip python3-dev libmysqlclient-dev # Configuration et installation de mysql. Le mot de passe root est le même que # le mot de passe pour l'utilisateur local - pour rappel, ceci est une instance @@ -42,7 +42,7 @@ chown vagrant: ~vagrant/.bash_profile cd /vagrant # Installation des dépendances python -sudo -H -u vagrant pip install --user -r requirements.txt -r requirements-devel.txt +sudo -H -u vagrant pip3 install --user -r requirements.txt -r requirements-devel.txt # Préparation de Django -sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD python manage.py migrate +sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD python3 manage.py migrate From aa95263fc9a5057bcd771824de56e47680bf7c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 9 Jul 2016 12:52:53 +0200 Subject: [PATCH 05/12] Fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - La fonction de hashage dans `bda/views` ne fonctionnait plus en py3 - L'attribut `tirage` des participants a été supprimé lors du dernier merge avec master. --- bda/models.py | 9 +++++---- bda/views.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bda/models.py b/bda/models.py index d7d64db0..c0eafc1a 100644 --- a/bda/models.py +++ b/bda/models.py @@ -115,6 +115,7 @@ PAYMENT_TYPES = ( ) +@python_2_unicode_compatible class Participant(models.Model): user = models.ForeignKey(User) choices = models.ManyToManyField(Spectacle, @@ -123,14 +124,14 @@ class Participant(models.Model): attributions = models.ManyToManyField(Spectacle, through="Attribution", related_name="attributed_to") - paid = models.BooleanField(u"A payé", default=False) - paymenttype = models.CharField(u"Moyen de paiement", + paid = models.BooleanField("A payé", default=False) + paymenttype = models.CharField("Moyen de paiement", max_length=6, choices=PAYMENT_TYPES, blank=True) tirage = models.ForeignKey(Tirage) - def __unicode__(self): - return u"%s" % (self.user) + def __str__(self): + return "%s" % (self.user) DOUBLE_CHOICES = ( ("1", "1 place"), diff --git a/bda/views.py b/bda/views.py index 1ca76a5a..d9b63615 100644 --- a/bda/views.py +++ b/bda/views.py @@ -65,7 +65,7 @@ def etat_places(request, tirage_id): def _hash_queryset(queryset): - data = serializers.serialize("json", queryset) + data = serializers.serialize("json", queryset).encode() hasher = hashlib.sha256() hasher.update(data) return hasher.hexdigest() From 4c32ba6307371b8a08d80b96e3b2ca800c7e1ad1 Mon Sep 17 00:00:00 2001 From: xapantu Date: Sat, 9 Jul 2016 19:49:24 -0700 Subject: [PATCH 06/12] assumons le pep8 --- bda/forms.py | 2 +- bda/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 9c73ff5f..60efa029 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -36,7 +36,7 @@ class TokenForm(forms.Form): class SpectacleModelChoiceField(forms.ModelChoiceField): def label_from_instance(self, obj): return "%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), - obj.location, obj.price) + obj.location, obj.price) class ResellForm(forms.Form): diff --git a/bda/models.py b/bda/models.py index c0eafc1a..8e353762 100644 --- a/bda/models.py +++ b/bda/models.py @@ -163,7 +163,7 @@ class ChoixSpectacle(models.Model): verbose_name_plural = "voeux" -@python2_unicode_compatible +@python_2_unicode_compatible class Attribution(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="attribues") From aa6e5e5479390dddaafc247ff9f2d0e4eacd9c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 10 Jul 2016 10:46:45 +0200 Subject: [PATCH 07/12] Oublis --- bda/models.py | 6 +++--- gestioncof/models.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bda/models.py b/bda/models.py index 8e353762..7d92897e 100644 --- a/bda/models.py +++ b/bda/models.py @@ -108,10 +108,10 @@ class Spectacle(models.Model): return members.values() PAYMENT_TYPES = ( - ("cash", u"Cash"), + ("cash", "Cash"), ("cb", "CB"), - ("cheque", u"Chèque"), - ("autre", u"Autre"), + ("cheque", "Chèque"), + ("autre", "Autre"), ) diff --git a/gestioncof/models.py b/gestioncof/models.py index ccb85bad..0c967a5b 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -66,7 +66,7 @@ class CofProfile(models.Model): petits_cours_accept = models.BooleanField( "Recevoir des petits cours", default=False) petits_cours_remarques = models.TextField( - _(u"Remarques et précisions pour les petits cours"), + _("Remarques et précisions pour les petits cours"), blank=True, default="") class Meta: From 210c6d7712eceeba68b899c6f0fc1e60f3a50c02 Mon Sep 17 00:00:00 2001 From: Basile Clement Date: Fri, 15 Jul 2016 00:02:56 +0200 Subject: [PATCH 08/12] Update Py3 compat --- apache/wsgi.py | 6 +++ bda/admin.py | 10 +++-- bda/algorithm.py | 3 +- bda/autocomplete_light_registry.py | 4 ++ bda/forms.py | 4 +- bda/models.py | 5 ++- bda/tests.py | 6 +++ bda/urls.py | 4 ++ bda/views.py | 5 ++- cof/settings_dev.py | 7 ++- cof/urls.py | 14 +++--- gestioncof/admin.py | 8 ++-- gestioncof/autocomplete.py | 4 ++ gestioncof/autocomplete_light_registry.py | 4 ++ gestioncof/csv_views.py | 4 ++ gestioncof/decorators.py | 4 ++ gestioncof/forms.py | 4 +- gestioncof/models.py | 25 ++++++----- gestioncof/petits_cours_models.py | 52 ++++++++++++----------- gestioncof/petits_cours_views.py | 8 ++-- gestioncof/shared.py | 6 +++ gestioncof/templatetags/utils.py | 4 ++ gestioncof/tests.py | 5 +++ gestioncof/urls.py | 6 +++ gestioncof/views.py | 39 +++-------------- gestioncof/widgets.py | 4 ++ sync_clipper.py | 5 ++- 27 files changed, 155 insertions(+), 95 deletions(-) diff --git a/apache/wsgi.py b/apache/wsgi.py index b7a1eb92..177542a8 100644 --- a/apache/wsgi.py +++ b/apache/wsgi.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + """ WSGI config for myproject project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -5,6 +7,10 @@ For more information on this file, see https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ """ +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + import os from django.core.wsgi import get_wsgi_application diff --git a/bda/admin.py b/bda/admin.py index cc4746ca..8f5915d5 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.core.mail import send_mail @@ -87,7 +89,7 @@ Le Bureau des Arts name = member.user.get_full_name() mail = mail % name else: - mail = u"""Cher-e %s, + 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 : @@ -149,8 +151,8 @@ class AttributionAdminForm(forms.ModelForm): if participant and spectacle: if participant.tirage != spectacle.tirage: raise forms.ValidationError( - u"Erreur : le participant et le spectacle n'appartiennent" - u"pas au même tirage") + "Erreur : le participant et le spectacle n'appartiennent" + "pas au même tirage") return cleaned_data diff --git a/bda/algorithm.py b/bda/algorithm.py index 4a2dbdcc..bf9b690f 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -1,6 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.db.models import Max diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py index aa6d4d57..6c2f3ea6 100644 --- a/bda/autocomplete_light_registry.py +++ b/bda/autocomplete_light_registry.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals import autocomplete_light diff --git a/bda/forms.py b/bda/forms.py index 60efa029..9f5e3890 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django import forms diff --git a/bda/models.py b/bda/models.py index 7d92897e..46b90b99 100644 --- a/bda/models.py +++ b/bda/models.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals import calendar @@ -140,6 +142,7 @@ DOUBLE_CHOICES = ( ) +@python_2_unicode_compatible class ChoixSpectacle(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="participants") diff --git a/bda/tests.py b/bda/tests.py index 501deb77..22efc5a2 100644 --- a/bda/tests.py +++ b/bda/tests.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -5,6 +6,11 @@ when you run "manage.py test". Replace this with more appropriate tests for your application. """ +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + from django.test import TestCase diff --git a/bda/urls.py b/bda/urls.py index 268bb352..4e5811a1 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -1,5 +1,9 @@ # -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + from django.conf.urls import url, patterns from bda.views import SpectacleListView diff --git a/bda/views.py b/bda/views.py index d9b63615..fbf75359 100644 --- a/bda/views.py +++ b/bda/views.py @@ -1,6 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.shortcuts import render, get_object_or_404 @@ -195,7 +196,7 @@ def do_tirage(request, tirage_id): tirage_elt = get_object_or_404(Tirage, id=tirage_id) form = TokenForm(request.POST) if not form.is_valid(): - return tirage(request) + return tirage(request, tirage_id) tirage_elt.token = form.cleaned_data['token'] tirage_elt.save() start = time.time() diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 1ef05f8c..502cb0ee 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -1,5 +1,4 @@ -# -*-coding:utf-8 -* - +# -*- coding: utf-8 -*- """ Django settings for cof project. @@ -10,6 +9,10 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os diff --git a/cof/urls.py b/cof/urls.py index 16c6a5f6..ee9d8457 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -1,17 +1,17 @@ -# -*-coding:utf-8 -* +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.conf import settings from django.conf.urls import patterns, include, url from django.conf.urls.static import static +from django.contrib import admin +from django.views.generic.base import TemplateView import autocomplete_light -from django.contrib import admin - -from django.views.generic.base import TemplateView - from gestioncof.urls import export_patterns, petitcours_patterns, \ surveys_patterns, events_patterns @@ -77,7 +77,7 @@ urlpatterns = patterns( url(r'^utile_bda/bda_revente$', 'gestioncof.views.liste_bdarevente'), ) + \ (static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - if settings.DEBUG - else []) + if settings.DEBUG + else []) # Si on est en production, MEDIA_ROOT est servi par Apache. # Il faut dire à Django de servir MEDIA_ROOT lui-même en développement. diff --git a/gestioncof/admin.py b/gestioncof/admin.py index fb188f4b..86935f64 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.contrib import admin @@ -15,8 +17,8 @@ import django.utils.six as six import autocomplete_light -def add_link_field(target_model='', field='', link_text=unicode, - desc_text=unicode): +def add_link_field(target_model='', field='', link_text=six.text_type, + desc_text=six.text_type): def add_link(cls): reverse_name = target_model or cls.model.__name__.lower() diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 248a6ae7..5b4616be 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django import shortcuts diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index 1b211691..f2a2ca6e 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals import autocomplete_light diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py index f8037413..c1d82aca 100644 --- a/gestioncof/csv_views.py +++ b/gestioncof/csv_views.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals import csv diff --git a/gestioncof/decorators.py b/gestioncof/decorators.py index e5416e32..d7e70608 100644 --- a/gestioncof/decorators.py +++ b/gestioncof/decorators.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django_cas_ng.decorators import user_passes_test diff --git a/gestioncof/forms.py b/gestioncof/forms.py index 7479586e..ce3a1b9e 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django import forms diff --git a/gestioncof/models.py b/gestioncof/models.py index 0c967a5b..8d660a53 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.db import models @@ -34,24 +36,21 @@ TYPE_COMMENT_FIELD = ( ) -def choices_length(choices): - return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0) - - +@python_2_unicode_compatible class CofProfile(models.Model): user = models.OneToOneField(User, related_name="profile") login_clipper = models.CharField("Login clipper", max_length=8, blank=True) is_cof = models.BooleanField("Membre du COF", default=False) num = models.IntegerField("Numéro d'adhérent", blank=True, default=0) phone = models.CharField("Téléphone", max_length=20, blank=True) - occupation = models.CharField(_(u"Occupation"), + occupation = models.CharField(_("Occupation"), default="1A", choices=OCCUPATION_CHOICES, max_length=choices_length( OCCUPATION_CHOICES)) - departement = models.CharField(_(u"Département"), max_length=50, + departement = models.CharField(_("Département"), max_length=50, blank=True) - type_cotiz = models.CharField(_(u"Type de cotisation"), + type_cotiz = models.CharField(_("Type de cotisation"), default="normalien", choices=TYPE_COTIZ_CHOICES, max_length=choices_length( @@ -83,6 +82,7 @@ def create_user_profile(sender, instance, created, **kwargs): post_save.connect(create_user_profile, sender=User) +@python_2_unicode_compatible class Club(models.Model): name = models.CharField("Nom", max_length=200) description = models.TextField("Description") @@ -141,6 +141,7 @@ class EventCommentField(models.Model): return six.text_type(self.name) +@python_2_unicode_compatible class EventCommentValue(models.Model): commentfield = models.ForeignKey(EventCommentField, related_name="values") registration = models.ForeignKey("EventRegistration", @@ -187,9 +188,9 @@ class EventRegistration(models.Model): verbose_name = "Inscription" unique_together = ("user", "event") - def __unicode__(self): - return u"Inscription de %s à %s" % (unicode(self.user), - unicode(self.event.title)) + def __str__(self): + return "Inscription de %s à %s" % (six.text_type(self.user), + six.text_type(self.event.title)) @python_2_unicode_compatible @@ -231,6 +232,7 @@ class SurveyQuestionAnswer(models.Model): return six.text_type(self.answer) +@python_2_unicode_compatible class SurveyAnswer(models.Model): user = models.ForeignKey(User) survey = models.ForeignKey(Survey) @@ -242,6 +244,7 @@ class SurveyAnswer(models.Model): unique_together = ("user", "survey") +@python_2_unicode_compatible class Clipper(models.Model): username = models.CharField("Identifiant", max_length=20) fullname = models.CharField("Nom complet", max_length=200) diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index b8487478..e9c2943d 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.db import models @@ -39,11 +41,11 @@ class PetitCoursSubject(models.Model): @python_2_unicode_compatible class PetitCoursAbility(models.Model): user = models.ForeignKey(User) - matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière")) - niveau = models.CharField(_(u"Niveau"), + matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) + niveau = models.CharField(_("Niveau"), choices=LEVELS_CHOICES, max_length=choices_length(LEVELS_CHOICES)) - agrege = models.BooleanField(_(u"Agrégé"), default=False) + agrege = models.BooleanField(_("Agrégé"), default=False) class Meta: verbose_name = "Compétence petits cours" @@ -56,41 +58,41 @@ class PetitCoursAbility(models.Model): @python_2_unicode_compatible class PetitCoursDemande(models.Model): - name = models.CharField(_(u"Nom/prénom"), max_length=200) - email = models.CharField(_(u"Adresse email"), max_length=300) - phone = models.CharField(_(u"Téléphone (facultatif)"), + name = models.CharField(_("Nom/prénom"), max_length=200) + email = models.CharField(_("Adresse email"), max_length=300) + phone = models.CharField(_("Téléphone (facultatif)"), max_length=20, blank=True) quand = models.CharField( - _(u"Quand ?"), - help_text=_(u"Indiquez ici la période désirée pour les petits" + _("Quand ?"), + help_text=_("Indiquez ici la période désirée pour les petits" " cours (vacances scolaires, semaine, week-end)."), max_length=300, blank=True) freq = models.CharField( - _(u"Fréquence"), - help_text=_(u"Indiquez ici la fréquence envisagée " + _("Fréquence"), + help_text=_("Indiquez ici la fréquence envisagée " + "(hebdomadaire, 2 fois par semaine, ...)"), max_length=300, blank=True) lieu = models.CharField( - _(u"Lieu (si préférence)"), - help_text=_(u"Si vous avez avez une préférence sur le lieu."), + _("Lieu (si préférence)"), + help_text=_("Si vous avez avez une préférence sur le lieu."), max_length=300, blank=True) matieres = models.ManyToManyField( - PetitCoursSubject, verbose_name=_(u"Matières"), + PetitCoursSubject, verbose_name=_("Matières"), related_name="demandes") - agrege_requis = models.BooleanField(_(u"Agrégé requis"), default=False) - niveau = models.CharField(_(u"Niveau"), + agrege_requis = models.BooleanField(_("Agrégé requis"), default=False) + niveau = models.CharField(_("Niveau"), default="", choices=LEVELS_CHOICES, max_length=choices_length(LEVELS_CHOICES)) - remarques = models.TextField(_(u"Remarques et précisions"), blank=True) + remarques = models.TextField(_("Remarques et précisions"), blank=True) - traitee = models.BooleanField(_(u"Traitée"), default=False) + traitee = models.BooleanField(_("Traitée"), default=False) traitee_par = models.ForeignKey(User, blank=True, null=True) - processed = models.DateTimeField(_(u"Date de traitement"), + processed = models.DateTimeField(_("Date de traitement"), blank=True, null=True) - created = models.DateTimeField(_(u"Date de création"), auto_now_add=True) + created = models.DateTimeField(_("Date de création"), auto_now_add=True) class Meta: verbose_name = "Demande de petits cours" @@ -105,10 +107,10 @@ class PetitCoursDemande(models.Model): class PetitCoursAttribution(models.Model): user = models.ForeignKey(User) demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande")) - matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière")) - date = models.DateTimeField(_(u"Date d'attribution"), auto_now_add=True) + matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) + date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True) rank = models.IntegerField("Rang dans l'email") - selected = models.BooleanField(_(u"Sélectionné par le demandeur"), + selected = models.BooleanField(_("Sélectionné par le demandeur"), default=False) class Meta: @@ -116,7 +118,7 @@ class PetitCoursAttribution(models.Model): verbose_name_plural = "Attributions de petits cours" def __str__(self): - return u"Attribution de la demande %d à %s pour %s" \ + return "Attribution de la demande %d à %s pour %s" \ % (self.demande.id, self.user.username, self.matiere) @@ -130,6 +132,6 @@ class PetitCoursAttributionCounter(models.Model): verbose_name = "Compteur d'attribution de petits cours" verbose_name_plural = "Compteurs d'attributions de petits cours" - def __unicode__(self): + def __str__(self): return "%d demandes envoyées à %s pour %s" \ % (self.count, self.user.username, self.matiere) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 7cba7ae1..b0f64d37 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.shortcuts import render, get_object_or_404, redirect @@ -183,12 +185,12 @@ def _traitement_other_preparing(request, demande): if choice == -1: continue if choice not in candidates: - errors.append(u"Choix invalide pour la proposition %d" + errors.append("Choix invalide pour la proposition %d" "en %s" % (choice_id + 1, matiere)) continue user = candidates[choice] if user in proposals[matiere]: - errors.append(u"La proposition %d en %s est un doublon" + errors.append("La proposition %d en %s est un doublon" % (choice_id + 1, matiere)) continue proposals[matiere].append(user) diff --git a/gestioncof/shared.py b/gestioncof/shared.py index 4fb2e4bc..fc901d50 100644 --- a/gestioncof/shared.py +++ b/gestioncof/shared.py @@ -1,3 +1,9 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + from django.contrib.sites.models import Site from django.conf import settings from django_cas_ng.backends import CASBackend diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 4785c822..223f208b 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django import template diff --git a/gestioncof/tests.py b/gestioncof/tests.py index 501deb77..a83ebffc 100644 --- a/gestioncof/tests.py +++ b/gestioncof/tests.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". @@ -5,6 +6,10 @@ when you run "manage.py test". Replace this with more appropriate tests for your application. """ +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + from django.test import TestCase diff --git a/gestioncof/urls.py b/gestioncof/urls.py index 787dd80f..5cea2f8e 100644 --- a/gestioncof/urls.py +++ b/gestioncof/urls.py @@ -1,3 +1,9 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + from django.conf.urls import url from gestioncof.petits_cours_views import DemandeListView diff --git a/gestioncof/views.py b/gestioncof/views.py index dc05d816..9dc1615e 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -1,5 +1,7 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals import unicodecsv @@ -280,35 +282,6 @@ def survey_status(request, survey_id): "form": form}) -class UserProfileForm(forms.ModelForm): - first_name = forms.CharField(label=_('Prénom'), max_length=30) - last_name = forms.CharField(label=_('Nom'), max_length=30) - - def __init__(self, *args, **kw): - super(UserProfileForm, self).__init__(*args, **kw) - self.fields['first_name'].initial = self.instance.user.first_name - self.fields['last_name'].initial = self.instance.user.last_name - - self.fields.keyOrder = [ - 'first_name', - 'last_name', - 'phone', - 'mailing_cof', - 'mailing_bda', - 'mailing_bda_revente', - ] - - def save(self, *args, **kw): - super(UserProfileForm, self).save(*args, **kw) - self.instance.user.first_name = self.cleaned_data.get('first_name') - self.instance.user.last_name = self.cleaned_data.get('last_name') - self.instance.user.save() - - class Meta: - model = CofProfile - fields = ("phone", "mailing_cof", "mailing_bda", "mailing_bda_revente",) ->>>>>>> Compatibilité python 3 - @login_required def profile(request): success = False @@ -523,7 +496,7 @@ def export_members(request): bits = [profile.num, user.username, user.first_name, user.last_name, user.email, profile.phone, profile.occupation, profile.departement, profile.type_cotiz] - writer.writerow([unicode(bit) for bit in bits]) + writer.writerow([six.text_type(bit) for bit in bits]) return response @@ -543,7 +516,7 @@ def csv_export_mega(filename, qs): profile.phone, profile.num, profile.comments if profile.comments else "", comments] - writer.writerow([unicode(bit) for bit in bits]) + writer.writerow([six.text_type(bit) for bit in bits]) return response @@ -563,7 +536,7 @@ def export_mega_remarksonly(request): profile = user.profile bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments, val.content] - writer.writerow([unicode(bit) for bit in bits]) + writer.writerow([six.text_type(bit) for bit in bits]) return response diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index d819f5a2..758fc4ad 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +from __future__ import division +from __future__ import print_function from __future__ import unicode_literals from django.forms.widgets import Widget diff --git a/sync_clipper.py b/sync_clipper.py index 78a88e76..d9620b2d 100644 --- a/sync_clipper.py +++ b/sync_clipper.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- -from __future__ import print_function, unicode_literals +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals import os import sys From 4d27d853845607c3eafaf574ee86f683ee9da180 Mon Sep 17 00:00:00 2001 From: Basile Clement Date: Fri, 15 Jul 2016 00:24:40 +0200 Subject: [PATCH 09/12] Keep using python2 by default on Vagrant install for now --- provisioning/bootstrap.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index ce3ef1e7..dde6e24a 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -8,7 +8,7 @@ DBNAME="cof_gestion" DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" # Installation de paquets utiles -apt-get update && apt-get install -y mercurial python3-pip python3-dev libmysqlclient-dev +apt-get update && apt-get install -y mercurial python-pip python-dev libmysqlclient-dev # Configuration et installation de mysql. Le mot de passe root est le même que # le mot de passe pour l'utilisateur local - pour rappel, ceci est une instance @@ -42,7 +42,7 @@ chown vagrant: ~vagrant/.bash_profile cd /vagrant # Installation des dépendances python -sudo -H -u vagrant pip3 install --user -r requirements.txt -r requirements-devel.txt +sudo -H -u vagrant pip install --user -r requirements.txt -r requirements-devel.txt # Préparation de Django -sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD python3 manage.py migrate +sudo -H -u vagrant DJANGO_SETTINGS_MODULE='cof.settings_dev' DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD python manage.py migrate From 73eac1886a80fa2b3725b29a5b0602aed321363c Mon Sep 17 00:00:00 2001 From: Basile Clement Date: Fri, 15 Jul 2016 01:18:31 +0200 Subject: [PATCH 10/12] Fix semantic error in events `gestioncof.views.registration` was using an `event` variable that was not properly defined. Due to a semantics oddity of python2, the value used was from a previous and (somewhat) unrelated list comprehension. --- gestioncof/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gestioncof/views.py b/gestioncof/views.py index 11d15d53..f3d677d9 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -453,13 +453,13 @@ def registration(request): (current_registration, created_reg) = \ EventRegistration.objects.get_or_create(user=member, event=form.event) - update_event_form_comments(event, form, current_registration) + update_event_form_comments(form.event, form, current_registration) current_registration.options = all_choices current_registration.paid = \ (form.cleaned_data['status'] == 'paid') current_registration.save() - if event.title == "Mega 15" and created_reg: - field = EventCommentField.objects.get(event=event, + if form.event.title == "Mega 15" and created_reg: + field = EventCommentField.objects.get(event=form.event, name="Commentaires") try: comments = EventCommentValue.objects.get( From c3631e2cd59d34429a76f8e3f3cebd46e627513b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 15 Jul 2016 02:20:58 +0200 Subject: [PATCH 11/12] =?UTF-8?q?Am=C3=A9liorations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/management/commands/sendrappels.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py index e66b0b23..1e8da240 100644 --- a/bda/management/commands/sendrappels.py +++ b/bda/management/commands/sendrappels.py @@ -14,7 +14,7 @@ class Command(BaseCommand): def handle(self, *args, **options): now = timezone.now() - delay = timedelta(4) + delay = timedelta(days=4) shows = Spectacle.objects \ .filter(date__range=(now, now+delay)) \ .filter(tirage__active=True) \ @@ -22,8 +22,6 @@ class Command(BaseCommand): .all() for show in shows: show.send_rappel() - show.rappel_sent = now - show.save() self.stdout.write( 'Mails de rappels pour %s envoyés avec succès.' % show) if not shows: From ea6e7a14720f05ed51d6b4ed7b0dfee8a38c1807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 15 Jul 2016 20:01:45 +0200 Subject: [PATCH 12/12] =?UTF-8?q?Ajoute=20des=20fonctions=20`=5F=5Fstr=5F?= =?UTF-8?q?=5F`=20l=C3=A0=20o=C3=B9=20=C3=A7a=20manque?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/models.py | 7 ++++++- gestioncof/models.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bda/models.py b/bda/models.py index 46b90b99..41037643 100644 --- a/bda/models.py +++ b/bda/models.py @@ -133,7 +133,7 @@ class Participant(models.Model): tirage = models.ForeignKey(Tirage) def __str__(self): - return "%s" % (self.user) + return "%s - %s" % (self.user, self.tirage.title) DOUBLE_CHOICES = ( ("1", "1 place"), @@ -159,6 +159,11 @@ class ChoixSpectacle(models.Model): return self.double_choice == "autoquit" autoquit = property(get_autoquit) + def __str__(self): + return "Vœux de %s pour %s" % ( + self.participant.user.get_full_name, + self.spectacle.title) + class Meta: ordering = ("priority",) unique_together = (("participant", "spectacle",),) diff --git a/gestioncof/models.py b/gestioncof/models.py index 8d660a53..cf3742f1 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -89,6 +89,9 @@ class Club(models.Model): respos = models.ManyToManyField(User, related_name="clubs_geres") membres = models.ManyToManyField(User, related_name="clubs") + def __str__(self): + return self.name + @python_2_unicode_compatible class CustomMail(models.Model): @@ -148,6 +151,9 @@ class EventCommentValue(models.Model): related_name="comments") content = models.TextField("Contenu", blank=True, null=True) + def __str__(self): + return "Commentaire de %s" % self.commentfield + @python_2_unicode_compatible class EventOption(models.Model): @@ -243,8 +249,16 @@ class SurveyAnswer(models.Model): verbose_name = "Réponses" unique_together = ("user", "survey") + def __str__(self): + return "Réponse de %s sondage %s" % ( + self.user.get_full_name(), + self.survey.title) + @python_2_unicode_compatible class Clipper(models.Model): username = models.CharField("Identifiant", max_length=20) fullname = models.CharField("Nom complet", max_length=200) + + def __str__(self): + return "Clipper %s" % self.username