From 4bd2562edf5a82c6d58a4c805bdbe4ff31483b6b Mon Sep 17 00:00:00 2001 From: Hugo Roussille Date: Wed, 13 Sep 2017 15:57:57 +0200 Subject: [PATCH 01/49] django-cors-headers for cross-domain AJAX --- cof/settings/common.py | 2 ++ requirements.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/cof/settings/common.py b/cof/settings/common.py index ba0b6044..fba32743 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -91,9 +91,11 @@ INSTALLED_APPS = [ 'modelcluster', 'taggit', 'kfet.cms', + 'corsheaders', ] MIDDLEWARE_CLASSES = [ + 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', diff --git a/requirements.txt b/requirements.txt index f3964212..b28b939e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ channels==1.1.5 python-dateutil wagtail==1.10.* wagtailmenus==2.2.* +django-cors-headers==2.1.0 # Production tools wheel From a4eedbc1a60c902301ef48559a58caf804ad5624 Mon Sep 17 00:00:00 2001 From: Hugo Roussille Date: Wed, 13 Sep 2017 18:21:34 +0200 Subject: [PATCH 02/49] Whitelist bda and cof apps for cross-domain --- cof/settings/common.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cof/settings/common.py b/cof/settings/common.py index fba32743..bac17653 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -197,6 +197,11 @@ AUTHENTICATION_BACKENDS = ( RECAPTCHA_USE_SSL = True +CORS_ORIGIN_REGEX_WHITELIST = ( + 'bda.ens.fr', + 'cof.ens.fr', +) + # Cache settings CACHES = { From 732e47707e96bb7047438edb1791511e89918fa1 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 17:25:58 +0200 Subject: [PATCH 03/49] Add unsubscribe option + list of current draws --- bda/forms.py | 41 +++++++++++++++++++-- bda/templates/bda/revente-tirages.html | 28 +++++++++++++++ bda/urls.py | 11 +++--- bda/views.py | 50 +++++++++++++++++++++++++- gestioncof/templates/home.html | 7 ++-- 5 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 bda/templates/bda/revente-tirages.html diff --git a/bda/forms.py b/bda/forms.py index c0417d1e..139ef45d 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -4,7 +4,7 @@ from django import forms from django.forms.models import BaseInlineFormSet from django.utils import timezone -from bda.models import Attribution, Spectacle +from bda.models import Attribution, Spectacle, SpectacleRevente class InscriptionInlineFormSet(BaseInlineFormSet): @@ -45,6 +45,9 @@ class AttributionModelMultipleChoiceField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): return "%s" % str(obj.spectacle) +class ReventeModelMultipleChoiceField(forms.ModelMultipleChoiceField): + def label_from_instance(self, obj): + return "%s" % str(obj.attribution.spectacle) class ResellForm(forms.Form): attributions = AttributionModelMultipleChoiceField( @@ -63,7 +66,6 @@ class ResellForm(forms.Form): 'participant__user') ) - class AnnulForm(forms.Form): attributions = AttributionModelMultipleChoiceField( label='', @@ -83,7 +85,6 @@ class AnnulForm(forms.Form): 'participant__user') ) - class InscriptionReventeForm(forms.Form): spectacles = forms.ModelMultipleChoiceField( queryset=Spectacle.objects.none(), @@ -98,6 +99,40 @@ class InscriptionReventeForm(forms.Form): .filter(date__gte=timezone.now()) ) +class ReventeTirageAnnulForm(forms.Form): + reventes = ReventeModelMultipleChoiceField( + label='', + queryset=SpectacleRevente.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False + ) + + def __init__(self, participant, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['reventes'].queryset = ( + participant.wanted.filter(soldTo__isnull=True) + .select_related('attribution__spectacle') + ) + + +class ReventeTirageForm(forms.Form): + reventes = ReventeModelMultipleChoiceField( + label='', + queryset=SpectacleRevente.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False + ) + + def __init__(self, participant, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['reventes'].queryset = ( + SpectacleRevente.objects.filter( + notif_sent=True, + shotgun=False, + tirage_done=False + ).exclude(answered_mail=participant) + .select_related('attribution__spectacle') + ) class SoldForm(forms.Form): attributions = AttributionModelMultipleChoiceField( diff --git a/bda/templates/bda/revente-tirages.html b/bda/templates/bda/revente-tirages.html new file mode 100644 index 00000000..bd738673 --- /dev/null +++ b/bda/templates/bda/revente-tirages.html @@ -0,0 +1,28 @@ +{% extends "base_title.html" %} +{% load bootstrap %} + +{% block realcontent %} + +

Tirages au sort de reventes

+{% if annulform.reventes %} +

Mes inscriptions

+
+ {% csrf_token %} + {{annulform|bootstrap}} +
+ +
+
+{% endif %} +
+{% if subform.reventes %} +

Tirages en cours

+
+ {% csrf_token %} + {{subform|bootstrap}} +
+ +
+
+{% endif %} +{% endblock %} diff --git a/bda/urls.py b/bda/urls.py index 876c84ea..51dd4235 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -32,16 +32,19 @@ urlpatterns = [ url(r'^spectacles/unpaid/(?P\d+)$', views.unpaid, name="bda-unpaid"), - url(r'^liste-revente/(?P\d+)$', + url(r'^revente/(?P\d+)/list$', views.list_revente, name="bda-liste-revente"), - url(r'^buy-revente/(?P\d+)$', + url(r'^revente/(?P\d+)/tirages$', + views.revente_tirages, + name="bda-revente-tirages"), + url(r'^revente/(?P\d+)/buy$', views.buy_revente, name="bda-buy-revente"), - url(r'^revente-interested/(?P\d+)$', + url(r'^revente/(?P\d+)/interested$', views.revente_interested, name='bda-revente-interested'), - url(r'^revente-immediat/(?P\d+)$', + url(r'^revente/(?P\d+)/immediat$', views.revente_shotgun, name="bda-shotgun"), url(r'^mails-rappel/(?P\d+)$', diff --git a/bda/views.py b/bda/views.py index 84b6c9d3..4b75c116 100644 --- a/bda/views.py +++ b/bda/views.py @@ -30,7 +30,7 @@ from bda.models import ( from bda.algorithm import Algorithm from bda.forms import ( TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm, - InscriptionInlineFormSet, + InscriptionInlineFormSet, ReventeTirageForm, ReventeTirageAnnulForm ) @@ -377,6 +377,7 @@ def revente(request, tirage_id): if not created: revente.seller = participant revente.date = timezone.now() + revente.wanted = Participant.objects.none() revente.soldTo = None revente.notif_sent = False revente.tirage_done = False @@ -442,6 +443,53 @@ def revente(request, tirage_id): "annulform": annulform, "resellform": resellform}) +@login_required +def revente_tirages(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + participant, _ = Participant.objects.get_or_create( + user=request.user, tirage=tirage) + unsub = 0 + subform = ReventeTirageForm(participant, prefix="subscribe") + annulform = ReventeTirageAnnulForm(participant, prefix="annul") + + if request.method == 'POST': + if "subscribe" in request.POST: + subform = ReventeTirageForm(participant, request.POST, + prefix="subscribe") + if subform.is_valid(): + sub = 0 + reventes = subform.cleaned_data['reventes'] + for revente in reventes: + revente.answered_mail.add(participant) + sub += 1 + if sub > 0: + plural = "s" if sub > 1 else "" + messages.success( + request, + "Tu as bien été inscrit à {} revente{}" + .format(sub, plural) + ) + elif "annul" in request.POST: + annulform = ReventeTirageAnnulForm(participant, request.POST, + prefix="annul") + if annulform.is_valid(): + unsub = 0 + reventes = annulform.cleaned_data['reventes'] + for revente in reventes: + revente.answered_mail.remove(participant) + unsub += 1 + if unsub > 0: + plural = "s" if unsub > 1 else "" + messages.success( + request, + "Tu as bien été désinscrit de {} revente{}" + .format(unsub, plural) + ) + + return render(request, "bda/revente-tirages.html", + {"annulform": annulform, "subform": subform}) + + @login_required def revente_interested(request, revente_id): revente = get_object_or_404(SpectacleRevente, id=revente_id) diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index acc04f30..f7ca57b5 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -43,9 +43,10 @@
  • État des demandes
  • {% else %}
  • Mes places
  • -
  • Revendre une place
  • -
  • S'inscrire à BdA-Revente
  • -
  • Places disponibles immédiatement
  • +
  • Gestion de mes reventes
  • +
  • Reventes en cours
  • +
  • S'inscrire à BdA-Revente
  • +
  • Places disponibles immédiatement
  • {% endif %} {% endfor %} From e74dbb11f1556a4ffb3cc42f83686a3a27cf5f45 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 18:39:45 +0200 Subject: [PATCH 04/49] Organize revente files and function names --- .../revente/confirm-shotgun.html} | 0 .../revente/confirmed.html} | 0 .../revente/mail-success.html} | 0 .../{reventes.html => revente/manage.html} | 0 .../revente/none.html} | 0 .../revente/notpaid.html} | 0 .../revente/shotgun.html} | 2 +- .../subscribe.html} | 0 .../tirages.html} | 0 .../revente/wrongtime.html} | 2 +- bda/urls.py | 30 +++++++++++-------- bda/views.py | 30 +++++++++---------- gestioncof/management/data/custommail.json | 2 +- gestioncof/templates/home.html | 6 ++-- 14 files changed, 38 insertions(+), 34 deletions(-) rename bda/templates/{revente-confirm.html => bda/revente/confirm-shotgun.html} (100%) rename bda/templates/{bda-interested.html => bda/revente/confirmed.html} (100%) rename bda/templates/{bda-success.html => bda/revente/mail-success.html} (100%) rename bda/templates/bda/{reventes.html => revente/manage.html} (100%) rename bda/templates/{bda-no-revente.html => bda/revente/none.html} (100%) rename bda/templates/{bda-notpaid.html => bda/revente/notpaid.html} (100%) rename bda/templates/{bda-shotgun.html => bda/revente/shotgun.html} (83%) rename bda/templates/bda/{liste-reventes.html => revente/subscribe.html} (100%) rename bda/templates/bda/{revente-tirages.html => revente/tirages.html} (100%) rename bda/templates/{bda-wrongtime.html => bda/revente/wrongtime.html} (86%) diff --git a/bda/templates/revente-confirm.html b/bda/templates/bda/revente/confirm-shotgun.html similarity index 100% rename from bda/templates/revente-confirm.html rename to bda/templates/bda/revente/confirm-shotgun.html diff --git a/bda/templates/bda-interested.html b/bda/templates/bda/revente/confirmed.html similarity index 100% rename from bda/templates/bda-interested.html rename to bda/templates/bda/revente/confirmed.html diff --git a/bda/templates/bda-success.html b/bda/templates/bda/revente/mail-success.html similarity index 100% rename from bda/templates/bda-success.html rename to bda/templates/bda/revente/mail-success.html diff --git a/bda/templates/bda/reventes.html b/bda/templates/bda/revente/manage.html similarity index 100% rename from bda/templates/bda/reventes.html rename to bda/templates/bda/revente/manage.html diff --git a/bda/templates/bda-no-revente.html b/bda/templates/bda/revente/none.html similarity index 100% rename from bda/templates/bda-no-revente.html rename to bda/templates/bda/revente/none.html diff --git a/bda/templates/bda-notpaid.html b/bda/templates/bda/revente/notpaid.html similarity index 100% rename from bda/templates/bda-notpaid.html rename to bda/templates/bda/revente/notpaid.html diff --git a/bda/templates/bda-shotgun.html b/bda/templates/bda/revente/shotgun.html similarity index 83% rename from bda/templates/bda-shotgun.html rename to bda/templates/bda/revente/shotgun.html index e10fae00..fae36c04 100644 --- a/bda/templates/bda-shotgun.html +++ b/bda/templates/bda/revente/shotgun.html @@ -5,7 +5,7 @@ {% if shotgun %}
      {% for spectacle in shotgun %} -
    • {{spectacle}}
    • +
    • {{spectacle}}
    • {% endfor %} {% else %}

      Pas de places disponibles immédiatement, désolé !

      diff --git a/bda/templates/bda/liste-reventes.html b/bda/templates/bda/revente/subscribe.html similarity index 100% rename from bda/templates/bda/liste-reventes.html rename to bda/templates/bda/revente/subscribe.html diff --git a/bda/templates/bda/revente-tirages.html b/bda/templates/bda/revente/tirages.html similarity index 100% rename from bda/templates/bda/revente-tirages.html rename to bda/templates/bda/revente/tirages.html diff --git a/bda/templates/bda-wrongtime.html b/bda/templates/bda/revente/wrongtime.html similarity index 86% rename from bda/templates/bda-wrongtime.html rename to bda/templates/bda/revente/wrongtime.html index dfafb05f..18c417a2 100644 --- a/bda/templates/bda-wrongtime.html +++ b/bda/templates/bda/revente/wrongtime.html @@ -6,7 +6,7 @@

      Le tirage au sort de cette revente a déjà été effectué !

      Si personne n'était intéressé, elle est maintenant disponible - ici.

      + ici.

      {% else %}

      Il n'est pas encore possible de s'inscrire à cette revente, réessaie dans quelque temps !

      {% endif %} diff --git a/bda/urls.py b/bda/urls.py index 51dd4235..7588187c 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -16,9 +16,6 @@ urlpatterns = [ url(r'^places/(?P\d+)$', views.places, name="bda-places-attribuees"), - url(r'^revente/(?P\d+)$', - views.revente, - name='bda-revente'), url(r'^etat-places/(?P\d+)$', views.etat_places, name='bda-etat-places'), @@ -32,21 +29,28 @@ urlpatterns = [ url(r'^spectacles/unpaid/(?P\d+)$', views.unpaid, name="bda-unpaid"), - url(r'^revente/(?P\d+)/list$', - views.list_revente, - name="bda-liste-revente"), + + # Urls BdA-Revente + + url(r'^revente/(?P\d+)/manage$', + views.revente_manage, + name='bda-revente-manage'), + url(r'^revente/(?P\d+)/subscribe$', + views.revente_subscribe, + name="bda-revente-subscribe"), url(r'^revente/(?P\d+)/tirages$', views.revente_tirages, name="bda-revente-tirages"), url(r'^revente/(?P\d+)/buy$', - views.buy_revente, - name="bda-buy-revente"), - url(r'^revente/(?P\d+)/interested$', - views.revente_interested, - name='bda-revente-interested'), - url(r'^revente/(?P\d+)/immediat$', + views.revente_buy, + name="bda-revente-buy"), + url(r'^revente/(?P\d+)/confirm$', + views.revente_confirm, + name='bda-revente-confirm'), + url(r'^revente/(?P\d+)/shotgun$', views.revente_shotgun, - name="bda-shotgun"), + name="bda-revente-shotgun"), + url(r'^mails-rappel/(?P\d+)$', views.send_rappel, name="bda-rappels" diff --git a/bda/views.py b/bda/views.py index 4b75c116..c0e64230 100644 --- a/bda/views.py +++ b/bda/views.py @@ -349,13 +349,13 @@ def tirage(request, tirage_id): @login_required -def revente(request, tirage_id): +def revente_manage(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) participant, created = Participant.objects.get_or_create( user=request.user, tirage=tirage) if not participant.paid: - return render(request, "bda-notpaid.html", {}) + return render(request, "bda/revente/notpaid.html", {}) resellform = ResellForm(participant, prefix='resell') annulform = AnnulForm(participant, prefix='annul') @@ -438,7 +438,7 @@ def revente(request, tirage_id): .filter( Q(revente__soldTo__isnull=True) | Q(revente__soldTo=participant)) - return render(request, "bda/reventes.html", + return render(request, "bda/revente/manage.html", {'tirage': tirage, 'overdue': overdue, "soldform": soldform, "annulform": annulform, "resellform": resellform}) @@ -486,27 +486,27 @@ def revente_tirages(request, tirage_id): .format(unsub, plural) ) - return render(request, "bda/revente-tirages.html", + return render(request, "bda/revente/tirages.html", {"annulform": annulform, "subform": subform}) @login_required -def revente_interested(request, revente_id): +def revente_confirm(request, revente_id): revente = get_object_or_404(SpectacleRevente, id=revente_id) 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", + return render(request, "bda/revente/wrongtime.html", {"revente": revente}) revente.answered_mail.add(participant) - return render(request, "bda-interested.html", + return render(request, "bda/revente/confirmed.html", {"spectacle": revente.attribution.spectacle, "date": revente.date_tirage}) @login_required -def list_revente(request, tirage_id): +def revente_subscribe(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) participant, _ = Participant.objects.get_or_create( user=request.user, tirage=tirage) @@ -560,11 +560,11 @@ def list_revente(request, tirage_id): ) messages.info(request, msg, extra_tags="safe") - return render(request, "bda/liste-reventes.html", {"form": form}) + return render(request, "bda/revente/subscribe.html", {"form": form}) @login_required -def buy_revente(request, spectacle_id): +def revente_buy(request, spectacle_id): spectacle = get_object_or_404(Spectacle, id=spectacle_id) tirage = spectacle.tirage participant, _ = Participant.objects.get_or_create( @@ -578,13 +578,13 @@ def buy_revente(request, spectacle_id): own_reventes = reventes.filter(seller=participant) if len(own_reventes) > 0: own_reventes[0].delete() - return HttpResponseRedirect(reverse("bda-shotgun", + return HttpResponseRedirect(reverse("bda-revente-shotgun", args=[tirage.id])) reventes_shotgun = reventes.filter(shotgun=True) if not reventes_shotgun: - return render(request, "bda-no-revente.html", {}) + return render(request, "bda/revente/none.html", {}) if request.POST: revente = random.choice(reventes_shotgun) @@ -601,11 +601,11 @@ def buy_revente(request, spectacle_id): [revente.seller.user.email], context=context, ) - return render(request, "bda-success.html", + return render(request, "bda/revente/mail-success.html", {"seller": revente.attribution.participant.user, "spectacle": spectacle}) - return render(request, "revente-confirm.html", + return render(request, "bda/revente/confirm-shotgun.html", {"spectacle": spectacle, "user": request.user}) @@ -629,7 +629,7 @@ def revente_shotgun(request, tirage_id): ) shotgun = [sp for sp in spectacles if len(sp.shotguns) > 0] - return render(request, "bda-shotgun.html", + return render(request, "bda/revente/shotgun.html", {"shotgun": shotgun}) diff --git a/gestioncof/management/data/custommail.json b/gestioncof/management/data/custommail.json index 9ee9b1ea..bf59e5f6 100644 --- a/gestioncof/management/data/custommail.json +++ b/gestioncof/management/data/custommail.json @@ -151,7 +151,7 @@ "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" + "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-confirm\" 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" } }, { diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index f7ca57b5..943ef780 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -43,10 +43,10 @@
    • État des demandes
    • {% else %}
    • Mes places
    • -
    • Gestion de mes reventes
    • +
    • Gestion de mes reventes
    • Reventes en cours
    • -
    • S'inscrire à BdA-Revente
    • -
    • Places disponibles immédiatement
    • +
    • S'inscrire à BdA-Revente
    • +
    • Places disponibles immédiatement
    • {% endif %}
    {% endfor %} From 919bcd197d077767bdc07355a70a84d39f8ebecf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 18:59:30 +0200 Subject: [PATCH 05/49] Small code QoL improvements --- bda/models.py | 10 ++++++++++ bda/views.py | 10 ++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/bda/models.py b/bda/models.py index 41462d70..5533e3bb 100644 --- a/bda/models.py +++ b/bda/models.py @@ -252,6 +252,16 @@ class SpectacleRevente(models.Model): class Meta: verbose_name = "Revente" + def reset(self): + """Réinitialise la revente pour permettre une remise sur le marché""" + self.seller = self.attribution.participant + self.date = timezone.now() + self.answered_mail.clear() + self.soldTo = None + self.notif_sent = False + self.tirage_done = False + self.shotgun = False + def send_notif(self): """ Envoie une notification pour indiquer la mise en vente d'une place sur diff --git a/bda/views.py b/bda/views.py index c0e64230..311d530a 100644 --- a/bda/views.py +++ b/bda/views.py @@ -375,13 +375,7 @@ def revente_manage(request, tirage_id): attribution=attribution, defaults={'seller': participant}) if not created: - revente.seller = participant - revente.date = timezone.now() - revente.wanted = Participant.objects.none() - revente.soldTo = None - revente.notif_sent = False - revente.tirage_done = False - revente.shotgun = False + revente.reset() context = { 'vendeur': participant.user, 'show': attribution.spectacle, @@ -495,7 +489,7 @@ def revente_confirm(request, revente_id): revente = get_object_or_404(SpectacleRevente, id=revente_id) 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: + if not revente.notif_sent or revente.shotgun: return render(request, "bda/revente/wrongtime.html", {"revente": revente}) From 1b0e4285ecbc7ea224cb7fad9c725365d4a9ba01 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 20:26:07 +0200 Subject: [PATCH 06/49] Reverse match fix --- gestioncof/management/data/custommail.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gestioncof/management/data/custommail.json b/gestioncof/management/data/custommail.json index bf59e5f6..029c03e0 100644 --- a/gestioncof/management/data/custommail.json +++ b/gestioncof/management/data/custommail.json @@ -161,7 +161,7 @@ "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" + "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-revente-buy\" show.id %}, \u00e0 la disposition de tous.\r\n\r\nChaleureusement,\r\nLe BdA" } }, { From 684603709e90e471f5528ab35f1efc2011145fb5 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 20:30:11 +0200 Subject: [PATCH 07/49] Class attributes and properties + more verbose log SpectacleRevente gets brand new properties and attributes to simplify code ; also, manage_reventes command output is more verbose --- bda/management/commands/manage_reventes.py | 48 ++++++++++++++-------- bda/models.py | 45 +++++++++++++++++--- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py index 0302ec4b..5a767604 100644 --- a/bda/management/commands/manage_reventes.py +++ b/bda/management/commands/manage_reventes.py @@ -6,7 +6,6 @@ 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 bda.models import SpectacleRevente @@ -21,23 +20,36 @@ class Command(BaseCommand): now = timezone.now() reventes = SpectacleRevente.objects.all() 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 \ - 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): + # Le spectacle est bientôt et on a pas encore envoyé de mail : + # on met la place au shotgun et on prévient. + if revente.is_urgent and not revente.notif_sent: + if revente.can_notif: + self.stdout.write(str(now)) + revente.mail_shotgun() + self.stdout.write( + "Mails de disponibilité immédiate envoyés " + "pour la revente [%s]" % revente + ) + + # Le spectacle est dans plus longtemps : on prévient + elif (revente.can_notif and 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.date_tirage and - not revente.tirage_done): + self.stdout.write( + "Mails d'inscription à la revente [%s] envoyés" + % revente + ) + + # On fait le tirage + elif (now >= revente.date_tirage and not revente.tirage_done): self.stdout.write(str(now)) - revente.tirage() - self.stdout.write("Tirage effectué, mails envoyés") + winner = revente.tirage() + self.stdout.write( + "Tirage effectué pour la revente [%s]" + % revente + ) + + if winner: + self.stdout.write("Gagnant : %s" % winner.user) + else: + self.stdout.write("Pas de gagnant ; place au shotgun") diff --git a/bda/models.py b/bda/models.py index 5533e3bb..b2882900 100644 --- a/bda/models.py +++ b/bda/models.py @@ -233,17 +233,46 @@ class SpectacleRevente(models.Model): default=False) shotgun = models.BooleanField("Disponible immédiatement", default=False) + #### + # Some class attributes + ### + # TODO : settings ? + + # Temps minimum entre le tirage et le spectacle + min_margin = timedelta(days=5) + + # Temps entre la création d'une revente et l'envoi du mail + remorse_time = timedelta(hours=1) + + # Temps min/max d'attente avant le tirage + max_wait_time = timedelta(days=3) + min_wait_time = timedelta(days=1) @property def date_tirage(self): """Renvoie la date du tirage au sort de la revente.""" - # L'acheteur doit être connu au plus 12h avant le spectacle + notif_time = self.date + self.remorse_time + remaining_time = (self.attribution.spectacle.date - - self.date - timedelta(hours=13)) - # Au minimum, on attend 2 jours avant le tirage - delay = min(remaining_time, timedelta(days=2)) - # Le vendeur a aussi 1h pour changer d'avis - return self.date + delay + timedelta(hours=1) + - notif_time - self.min_margin) + + delay = min(remaining_time, self.max_wait_time) + + return notif_time + delay + + @property + def is_urgent(self): + """ + Renvoie True iff la revente doit être mise au shotgun directement. + Plus précisément, on doit avoir min_margin + min_wait_time de marge. + """ + spectacle_date = self.attribution.spectacle.date + return (spectacle_date <= timezone.now() + self.min_margin + + self.min_wait_time) + + @property + def can_notif(self): + return (timezone.now() >= self.date + self.remorse_time) def __str__(self): return "%s -- %s" % (self.seller, @@ -353,8 +382,12 @@ class SpectacleRevente(models.Model): [inscrit.user.email] )) send_mass_custom_mail(datatuple) + + return winner + # Si personne ne veut de la place, elle part au shotgun else: self.shotgun = True + return None self.tirage_done = True self.save() From 6a6549e0d72937d9f5adaf7bf43ff090150b4891 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 23 Oct 2017 20:52:25 +0200 Subject: [PATCH 08/49] Add notif time In case of a gestioCOF bug, we keep the notification time in memory to still do the drawing 1-3 days after. --- bda/admin.py | 6 +++--- bda/forms.py | 4 ++-- bda/migrations/0012_notif_time.py | 28 ++++++++++++++++++++++++++++ bda/models.py | 29 +++++++++++++++++++++-------- bda/views.py | 14 +++++++------- 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 bda/migrations/0012_notif_time.py diff --git a/bda/admin.py b/bda/admin.py index 60d3c1ba..4f5d821a 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -225,7 +225,7 @@ class SpectacleReventeAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['answered_mail'].queryset = ( + self.fields['confirmed_entry'].queryset = ( Participant.objects .select_related('user', 'tirage') ) @@ -292,8 +292,8 @@ class SpectacleReventeAdmin(admin.ModelAdmin): revente.soldTo = None revente.notif_sent = False revente.tirage_done = False - if revente.answered_mail: - revente.answered_mail.clear() + if revente.confirmed_entry: + revente.confirmed_entry.clear() revente.save() self.message_user( request, diff --git a/bda/forms.py b/bda/forms.py index 139ef45d..11d05b0e 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -110,7 +110,7 @@ class ReventeTirageAnnulForm(forms.Form): def __init__(self, participant, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['reventes'].queryset = ( - participant.wanted.filter(soldTo__isnull=True) + participant.entered.filter(soldTo__isnull=True) .select_related('attribution__spectacle') ) @@ -130,7 +130,7 @@ class ReventeTirageForm(forms.Form): notif_sent=True, shotgun=False, tirage_done=False - ).exclude(answered_mail=participant) + ).exclude(confirmed_entry=participant) .select_related('attribution__spectacle') ) diff --git a/bda/migrations/0012_notif_time.py b/bda/migrations/0012_notif_time.py new file mode 100644 index 00000000..be66efd1 --- /dev/null +++ b/bda/migrations/0012_notif_time.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bda', '0011_tirage_appear_catalogue'), + ] + + operations = [ + migrations.RemoveField( + model_name='spectaclerevente', + name='answered_mail', + ), + migrations.AddField( + model_name='spectaclerevente', + name='confirmed_entry', + field=models.ManyToManyField(blank=True, related_name='entered', to='bda.Participant'), + ), + migrations.AddField( + model_name='spectaclerevente', + name='notif_time', + field=models.DateTimeField(blank=True, verbose_name="Moment d'envoi de la notification", null=True), + ), + ] diff --git a/bda/models.py b/bda/models.py index b2882900..2ad47dbf 100644 --- a/bda/models.py +++ b/bda/models.py @@ -218,9 +218,9 @@ class SpectacleRevente(models.Model): related_name="revente") date = models.DateTimeField("Date de mise en vente", default=timezone.now) - answered_mail = models.ManyToManyField(Participant, - related_name="wanted", - blank=True) + confirmed_entry = models.ManyToManyField(Participant, + related_name="entered", + blank=True) seller = models.ForeignKey(Participant, related_name="original_shows", verbose_name="Vendeur") @@ -229,8 +229,13 @@ class SpectacleRevente(models.Model): notif_sent = models.BooleanField("Notification envoyée", default=False) + + notif_time = models.DateTimeField("Moment d'envoi de la notification", + blank=True, null=True) + tirage_done = models.BooleanField("Tirage effectué", default=False) + shotgun = models.BooleanField("Disponible immédiatement", default=False) #### @@ -248,17 +253,23 @@ class SpectacleRevente(models.Model): max_wait_time = timedelta(days=3) min_wait_time = timedelta(days=1) + @property + def real_notif_time(self): + if self.notif_time: + return self.notif_time + else: + return self.date + self.remorse_time + @property def date_tirage(self): """Renvoie la date du tirage au sort de la revente.""" - notif_time = self.date + self.remorse_time remaining_time = (self.attribution.spectacle.date - - notif_time - self.min_margin) + - self.real_notif_time - self.min_margin) delay = min(remaining_time, self.max_wait_time) - return notif_time + delay + return self.real_notif_time + delay @property def is_urgent(self): @@ -285,7 +296,7 @@ class SpectacleRevente(models.Model): """Réinitialise la revente pour permettre une remise sur le marché""" self.seller = self.attribution.participant self.date = timezone.now() - self.answered_mail.clear() + self.confirmed_entry.clear() self.soldTo = None self.notif_sent = False self.tirage_done = False @@ -311,6 +322,7 @@ class SpectacleRevente(models.Model): ] send_mass_custom_mail(datatuple) self.notif_sent = True + self.notif_time = timezone.now() self.save() def mail_shotgun(self): @@ -332,6 +344,7 @@ class SpectacleRevente(models.Model): ] send_mass_custom_mail(datatuple) self.notif_sent = True + self.notif_time = timezone.now() # Flag inutile, sauf si l'horloge interne merde self.tirage_done = True self.shotgun = True @@ -343,7 +356,7 @@ class SpectacleRevente(models.Model): 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()) + inscrits = list(self.confirmed_entry.all()) spectacle = self.attribution.spectacle seller = self.seller diff --git a/bda/views.py b/bda/views.py index 311d530a..6ed22b21 100644 --- a/bda/views.py +++ b/bda/views.py @@ -420,8 +420,8 @@ def revente_manage(request, tirage_id): revente.notif_sent = False revente.tirage_done = False revente.shotgun = False - if revente.answered_mail: - revente.answered_mail.clear() + if revente.confirmed_entry: + revente.confirmed_entry.clear() revente.save() overdue = participant.attribution_set.filter( @@ -454,7 +454,7 @@ def revente_tirages(request, tirage_id): sub = 0 reventes = subform.cleaned_data['reventes'] for revente in reventes: - revente.answered_mail.add(participant) + revente.confirmed_entry.add(participant) sub += 1 if sub > 0: plural = "s" if sub > 1 else "" @@ -470,7 +470,7 @@ def revente_tirages(request, tirage_id): unsub = 0 reventes = annulform.cleaned_data['reventes'] for revente in reventes: - revente.answered_mail.remove(participant) + revente.confirmed_entry.remove(participant) unsub += 1 if unsub > 0: plural = "s" if unsub > 1 else "" @@ -493,7 +493,7 @@ def revente_confirm(request, revente_id): return render(request, "bda/revente/wrongtime.html", {"revente": revente}) - revente.answered_mail.add(participant) + revente.confirmed_entry.add(participant) return render(request, "bda/revente/confirmed.html", {"spectacle": revente.attribution.spectacle, "date": revente.date_tirage}) @@ -526,12 +526,12 @@ def revente_subscribe(request, tirage_id): # la revente ayant le moins d'inscrits min_resell = ( qset.filter(shotgun=False) - .annotate(nb_subscribers=Count('answered_mail')) + .annotate(nb_subscribers=Count('confirmed_entry')) .order_by('nb_subscribers') .first() ) if min_resell is not None: - min_resell.answered_mail.add(participant) + min_resell.confirmed_entry.add(participant) inscrit_revente.append(spectacle) success = True else: From 785555c05cc874dfc2a9542608c0e94baffccc2e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 26 Oct 2017 12:40:11 +0200 Subject: [PATCH 09/49] Misc fixes --- bda/forms.py | 10 ++++++++-- bda/migrations/0012_notif_time.py | 7 ++++--- bda/models.py | 11 ++++++----- bda/views.py | 33 +++++++++++-------------------- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 11d05b0e..2929f771 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -43,11 +43,13 @@ class TokenForm(forms.Form): class AttributionModelMultipleChoiceField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): - return "%s" % str(obj.spectacle) + return str(obj.spectacle) + class ReventeModelMultipleChoiceField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): - return "%s" % str(obj.attribution.spectacle) + return str(obj.attribution.spectacle) + class ResellForm(forms.Form): attributions = AttributionModelMultipleChoiceField( @@ -66,6 +68,7 @@ class ResellForm(forms.Form): 'participant__user') ) + class AnnulForm(forms.Form): attributions = AttributionModelMultipleChoiceField( label='', @@ -85,6 +88,7 @@ class AnnulForm(forms.Form): 'participant__user') ) + class InscriptionReventeForm(forms.Form): spectacles = forms.ModelMultipleChoiceField( queryset=Spectacle.objects.none(), @@ -99,6 +103,7 @@ class InscriptionReventeForm(forms.Form): .filter(date__gte=timezone.now()) ) + class ReventeTirageAnnulForm(forms.Form): reventes = ReventeModelMultipleChoiceField( label='', @@ -134,6 +139,7 @@ class ReventeTirageForm(forms.Form): .select_related('attribution__spectacle') ) + class SoldForm(forms.Form): attributions = AttributionModelMultipleChoiceField( label='', diff --git a/bda/migrations/0012_notif_time.py b/bda/migrations/0012_notif_time.py index be66efd1..ee777e35 100644 --- a/bda/migrations/0012_notif_time.py +++ b/bda/migrations/0012_notif_time.py @@ -11,11 +11,12 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RemoveField( + migrations.RenameField( model_name='spectaclerevente', - name='answered_mail', + old_name='answered_mail', + new_name='confirmed_entry', ), - migrations.AddField( + migrations.AlterField( model_name='spectaclerevente', name='confirmed_entry', field=models.ManyToManyField(blank=True, related_name='entered', to='bda.Participant'), diff --git a/bda/models.py b/bda/models.py index 2ad47dbf..59827621 100644 --- a/bda/models.py +++ b/bda/models.py @@ -168,6 +168,7 @@ class Participant(models.Model): def __str__(self): return "%s - %s" % (self.user, self.tirage.title) + DOUBLE_CHOICES = ( ("1", "1 place"), ("autoquit", "2 places si possible, 1 sinon"), @@ -292,15 +293,16 @@ class SpectacleRevente(models.Model): class Meta: verbose_name = "Revente" - def reset(self): + def reset(self, new_date=timezone.now()): """Réinitialise la revente pour permettre une remise sur le marché""" self.seller = self.attribution.participant - self.date = timezone.now() + self.date = new_date self.confirmed_entry.clear() self.soldTo = None self.notif_sent = False self.tirage_done = False self.shotgun = False + self.save() def send_notif(self): """ @@ -396,11 +398,10 @@ class SpectacleRevente(models.Model): )) send_mass_custom_mail(datatuple) - return winner - # Si personne ne veut de la place, elle part au shotgun else: + winner = None self.shotgun = True - return None self.tirage_done = True self.save() + return winner diff --git a/bda/views.py b/bda/views.py index 6ed22b21..fb1a2e82 100644 --- a/bda/views.py +++ b/bda/views.py @@ -5,7 +5,6 @@ import random import hashlib import time import json -from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail, send_custom_mail from custommail.models import CustomMail from django.shortcuts import render, get_object_or_404 @@ -14,6 +13,7 @@ from django.contrib import messages from django.db import transaction from django.core import serializers from django.db.models import Count, Q, Prefetch +from django.template.defaultfilters import pluralize from django.forms.models import inlineformset_factory from django.http import ( HttpResponseBadRequest, HttpResponseRedirect, JsonResponse @@ -376,6 +376,7 @@ def revente_manage(request, tirage_id): defaults={'seller': participant}) if not created: revente.reset() + context = { 'vendeur': participant.user, 'show': attribution.spectacle, @@ -414,15 +415,10 @@ def revente_manage(request, tirage_id): attributions = soldform.cleaned_data['attributions'] for attribution in attributions: if attribution.spectacle.date > timezone.now(): - revente = attribution.revente - revente.date = timezone.now() - timedelta(minutes=65) - revente.soldTo = None - revente.notif_sent = False - revente.tirage_done = False - revente.shotgun = False - if revente.confirmed_entry: - revente.confirmed_entry.clear() - revente.save() + # On antidate pour envoyer le mail plus vite + new_date = (timezone.now() + - SpectacleRevente.remorse_time) + revente.reset(new_date=new_date) overdue = participant.attribution_set.filter( spectacle__date__gte=timezone.now(), @@ -442,7 +438,6 @@ def revente_tirages(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) participant, _ = Participant.objects.get_or_create( user=request.user, tirage=tirage) - unsub = 0 subform = ReventeTirageForm(participant, prefix="subscribe") annulform = ReventeTirageAnnulForm(participant, prefix="annul") @@ -451,33 +446,29 @@ def revente_tirages(request, tirage_id): subform = ReventeTirageForm(participant, request.POST, prefix="subscribe") if subform.is_valid(): - sub = 0 reventes = subform.cleaned_data['reventes'] + count = reventes.count() for revente in reventes: revente.confirmed_entry.add(participant) - sub += 1 - if sub > 0: - plural = "s" if sub > 1 else "" + if count > 0: messages.success( request, "Tu as bien été inscrit à {} revente{}" - .format(sub, plural) + .format(count, pluralize(count)) ) elif "annul" in request.POST: annulform = ReventeTirageAnnulForm(participant, request.POST, prefix="annul") if annulform.is_valid(): - unsub = 0 reventes = annulform.cleaned_data['reventes'] + count = reventes.count() for revente in reventes: revente.confirmed_entry.remove(participant) - unsub += 1 - if unsub > 0: - plural = "s" if unsub > 1 else "" + if count > 0: messages.success( request, "Tu as bien été désinscrit de {} revente{}" - .format(unsub, plural) + .format(count, pluralize(count)) ) return render(request, "bda/revente/tirages.html", From f18959c0a1d643fab3b08921a004f158d4ba4720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 1 Nov 2017 17:26:40 +0100 Subject: [PATCH 10/49] BdA-Revente: meaningful names, some help tests --- bda/templates/bda/revente/manage.html | 58 +++++++++++++++++++----- bda/templates/bda/revente/subscribe.html | 39 ++++++++++------ bda/templates/bda/revente/tirages.html | 40 ++++++++++++---- bda/views.py | 18 ++++++++ gestioncof/static/css/cof.css | 11 +++++ gestioncof/templates/home.html | 6 +-- 6 files changed, 136 insertions(+), 36 deletions(-) diff --git a/bda/templates/bda/revente/manage.html b/bda/templates/bda/revente/manage.html index 0912babb..8162d55d 100644 --- a/bda/templates/bda/revente/manage.html +++ b/bda/templates/bda/revente/manage.html @@ -3,50 +3,84 @@ {% block realcontent %} -

    Revente de place

    +

    Gestion des places que je revends

    {% with resell_attributions=resellform.attributions annul_attributions=annulform.attributions sold_attributions=soldform.attributions %} {% if resellform.attributions %} +
    +

    Places non revendues

    - {% csrf_token %} - {{resellform|bootstrap}} +
    + + Cochez les places que vous souhaitez revendre, et validez. Vous aurez + ensuite 1h pour changer d'avis avant que la revente soit confirmée et + que les notifications soient envoyées aux intéressé·e·s. +
    +
    + {% csrf_token %} + {{ resellform|bootstrap }} +
    + +
    {% endif %} -
    + {% if annul_attributions or overdue %}

    Places en cours de revente

    + {% if annul_attributions %} +
    + + Vous pouvez annuler les places mises en vente il y a moins d'une heure. +
    + {% endif %} {% csrf_token %}
      {% for attrib in annul_attributions %} -
    • {{attrib.tag}} {{attrib.choice_label}}
    • +
    • {{ attrib.tag }} {{ attrib.choice_label }}
    • {% endfor %} {% for attrib in overdue %}
    • - {{attrib.spectacle}} + {{ attrib.spectacle }}
    • {% endfor %} +
    +
    +
    {% if annul_attributions %} {% endif %}
    + +
    {% endif %} -
    + {% if sold_attributions %}

    Places revendues

    -
    + +
    + + Pour chaque revente, vous devez soit l'annuler soit la confirmer pour + transférer la place la place à la personne tirée au sort. + + L'annulation sert par exemple à pouvoir remettre la place en jeu si + vous ne parvenez pas à entrer en contact avec la personne tirée au + sort. +
    +
    {% csrf_token %} - {{soldform|bootstrap}} - - - + {{ soldform|bootstrap }} +
    + + + {% endif %} {% if not resell_attributions and not annul_attributions and not overdue and not sold_attributions %}

    Plus de reventes possibles !

    diff --git a/bda/templates/bda/revente/subscribe.html b/bda/templates/bda/revente/subscribe.html index fcf57345..9a193908 100644 --- a/bda/templates/bda/revente/subscribe.html +++ b/bda/templates/bda/revente/subscribe.html @@ -4,28 +4,41 @@ {% block realcontent %}

    Inscriptions pour BdA-Revente

    +
    + + Cochez les spectacles pour lesquels vous souhaitez recevoir un + notification quand une place est disponible en revente.
    + Lorsque vous validez vos choix, si un tirage au sort est en cours pour + un des spectacles que vous avez sélectionné, vous serez automatiquement + inscrit à ce tirage. +
    +
    {% csrf_token %}
    -

    Spectacles

    -
    - - + + -
    -
      - {% for checkbox in form.spectacles %} -
    • {{checkbox}}
    • - {%endfor%} -
    -
    +
    +
      + {% for checkbox in form.spectacles %} +
    • {{ checkbox }}
    • + {% endfor %} +
    +
    - +
    + diff --git a/kfet/templates/kfet/category.html b/kfet/templates/kfet/category.html index 0ea96c8f..a31cc3cf 100644 --- a/kfet/templates/kfet/category.html +++ b/kfet/templates/kfet/category.html @@ -17,12 +17,15 @@ {% block main %}
    - +
    - + diff --git a/kfet/templates/kfet/checkout.html b/kfet/templates/kfet/checkout.html index 96373c49..c2c5e4bc 100644 --- a/kfet/templates/kfet/checkout.html +++ b/kfet/templates/kfet/checkout.html @@ -24,13 +24,16 @@ {% block main %}
    -
    Nom Nombre d'articlesPeut être majoréePeut être majorée
    +
    - - + + @@ -43,8 +46,12 @@ - - + + {% endfor %} diff --git a/kfet/templates/kfet/checkout_read.html b/kfet/templates/kfet/checkout_read.html index 12ba7e64..37a6e173 100644 --- a/kfet/templates/kfet/checkout_read.html +++ b/kfet/templates/kfet/checkout_read.html @@ -14,10 +14,13 @@ {% if not statements %} Pas de relevé {% else %} -
    Nom BalanceDéb. valid.Fin valid.Déb. valid.Fin valid. Protégée
    {{ checkout.balance}}€{{ checkout.valid_from }}{{ checkout.valid_to }} + {{ checkout.valid_from|date:'d/m/Y H:i' }} + + {{ checkout.valid_to|date:'d/m/Y H:i' }} + {{ checkout.is_protected|yesno }}
    +
    - + @@ -25,9 +28,9 @@ {% for statement in statements %} - diff --git a/kfet/templates/kfet/inventory.html b/kfet/templates/kfet/inventory.html index 237c45cd..f05dc32a 100644 --- a/kfet/templates/kfet/inventory.html +++ b/kfet/templates/kfet/inventory.html @@ -17,10 +17,13 @@ {% block main %}
    -
    Date/heureDate/heure Montant pris Montant laissé Erreur
    + - {{ statement.at }} + {{ statement.at|date:'d/m/Y H:i' }} {{ statement.amount_taken }}
    +
    - + @@ -28,9 +31,9 @@ {% for inventory in inventories %} - diff --git a/kfet/templates/kfet/inventory_read.html b/kfet/templates/kfet/inventory_read.html index dd5ceb2c..1edc21e0 100644 --- a/kfet/templates/kfet/inventory_read.html +++ b/kfet/templates/kfet/inventory_read.html @@ -27,7 +27,10 @@ {% block main %}
    -
    DateDate Par Nb articles
    + - {{ inventory.at }} + {{ inventory.at|date:'d/m/Y H:i' }} {{ inventory.by }}
    +
    @@ -36,25 +39,28 @@ - - {% for inventoryart in inventoryarts %} - {% ifchanged inventoryart.article.category %} - - - - {% endifchanged %} - - - - - + {% regroup inventoryarts by article.category as category_list %} + {% for category in category_list %} + + + - {% endfor %} - + + + {% for inventoryart in category.list %} + + + + + + + {% endfor %} + + {% endfor %}
    ArticleErreur
    {{ inventoryart.article.category.name }}
    - - {{ inventoryart.article.name }} - - {{ inventoryart.stock_old }}{{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
    {{ category.grouper.name }}
    + + {{ inventoryart.article.name }} + + {{ inventoryart.stock_old }}{{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
    diff --git a/kfet/templates/kfet/order.html b/kfet/templates/kfet/order.html index 53ef1bfb..0e4ed868 100644 --- a/kfet/templates/kfet/order.html +++ b/kfet/templates/kfet/order.html @@ -55,11 +55,14 @@

    Liste des commandes

    - +
    - - + + @@ -74,9 +77,9 @@ {% endif %} - diff --git a/kfet/templates/kfet/order_create.html b/kfet/templates/kfet/order_create.html index d95cafe3..e2e7c4cd 100644 --- a/kfet/templates/kfet/order_create.html +++ b/kfet/templates/kfet/order_create.html @@ -11,60 +11,79 @@ {% csrf_token %}
    -
    DateDate Fournisseur Inventaire
    + - {{ order.at }} + {{ order.at|date:'d/m/Y H:i' }} {{ order.supplier }}
    +
    - - - - + + + + - - - + + + {% for label in scale.get_labels %} - + {% endfor %} - - {% for form in formset %} - {% ifchanged form.category %} - - - - {% endifchanged %} - - {{ form.article }} - - {% for v_chunk in form.v_all %} - - {% endfor %} - - - - - - - + {% regroup formset by category_name as category_list %} + {% for category in category_list %} + + + - {% endfor %} - + + + {% for form in category.list %} + + {{ form.article }} + + {% for v_chunk in form.v_all %} + + {% endfor %} + + + + + + + + + {% endfor %} + + {% endfor %}
    ArticleVentes - - V. moy.
    - -
    E.T.
    - -
    Prév.
    - -
    + Ventes + + + V. moy. +
    + +
    + E.T. +
    + +
    + Prév. +
    + +
    StockBox
    - -
    Rec.
    - -
    Commande + Box +
    + +
    + Rec. +
    + +
    + Commande +
    {{ label }}{{ label }}
    {{ form.category_name }}
    {{ form.name }}{{ v_chunk }}{{ form.v_moy }}{{ form.v_et }}{{ form.v_prev }}{{ form.stock }}{{ form.box_capacity|default:"" }}{{ form.c_rec }}{{ form.quantity_ordered | add_class:"form-control" }}
    {{ category.grouper }}
    {{ form.name }}{{ v_chunk }}{{ form.v_moy }}{{ form.v_et }}{{ form.v_prev }}{{ form.stock }}{{ form.box_capacity|default:"" }}{{ form.c_rec }}{{ form.quantity_ordered|add_class:"form-control" }}
    {{ formset.management_form }} diff --git a/kfet/templates/kfet/order_read.html b/kfet/templates/kfet/order_read.html index 69b74420..9241c394 100644 --- a/kfet/templates/kfet/order_read.html +++ b/kfet/templates/kfet/order_read.html @@ -42,7 +42,10 @@

    Détails

    - +
    @@ -51,32 +54,35 @@ - - {% for orderart in orderarts %} - {% ifchanged orderart.article.category %} - - - - {% endifchanged %} - - - - - + {% regroup orderarts by article.category as category_list %} + {% for category in category_list %} + + + - {% endfor %} - + + + {% for orderart in category.list %} + + + + + + + {% endfor %} + + {% endfor %}
    ArticleReçu
    {{ orderart.article.category.name }}
    - - {{ orderart.article.name }} - - {{ orderart.quantity_ordered }} - {% if orderart.article.box_capacity %} - {# c'est une division ! #} - {% widthratio orderart.quantity_ordered orderart.article.box_capacity 1 %} - {% endif %} - - {{ orderart.quantity_received|default_if_none:'' }} -
    {{ category.grouper.name }}
    + + {{ orderart.article.name }} + + {{ orderart.quantity_ordered }} + {% if orderart.article.box_capacity %} + {# c'est une division ! #} + {% widthratio orderart.quantity_ordered orderart.article.box_capacity 1 %} + {% endif %} + + {{ orderart.quantity_received|default_if_none:'' }} +
    diff --git a/kfet/views.py b/kfet/views.py index f1dd6834..f0665ef6 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1839,7 +1839,7 @@ def order_create(request, pk): else: formset = cls_formset(initial=initial) - scale.label_fmt = "S -{rev_i}" + scale.label_fmt = "S-{rev_i}" return render(request, 'kfet/order_create.html', { 'supplier': supplier, From 212528011acd58b14dc64859b288d9b33caf5750 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Dec 2017 11:40:02 +0100 Subject: [PATCH 13/49] Add some tests --- bda/models.py | 63 +++++++++++++++++------------------ bda/tests/test_revente.py | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 bda/tests/test_revente.py diff --git a/bda/models.py b/bda/models.py index 59827621..1c081a56 100644 --- a/bda/models.py +++ b/bda/models.py @@ -352,7 +352,7 @@ class SpectacleRevente(models.Model): self.shotgun = True self.save() - def tirage(self): + def tirage(self, send_mails=True): """ Lance le tirage au sort associé à la revente. Un gagnant est choisi parmis les personnes intéressées par le spectacle. Les personnes sont @@ -366,37 +366,38 @@ 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, - } - datatuple.append(( - 'bda-revente-winner', - context, - settings.MAIL_DATA['revente']['FROM'], - [winner.user.email], - )) - datatuple.append(( - 'bda-revente-seller', - context, - settings.MAIL_DATA['revente']['FROM'], - [seller.user.email] - )) + if send_mails: + datatuple = [] + context = { + 'acheteur': winner.user, + 'vendeur': seller.user, + 'show': spectacle, + } + datatuple.append(( + 'bda-revente-winner', + context, + settings.MAIL_DATA['revente']['FROM'], + [winner.user.email], + )) + datatuple.append(( + 'bda-revente-seller', + context, + settings.MAIL_DATA['revente']['FROM'], + [seller.user.email] + )) - # Envoie un mail aux perdants - for inscrit in inscrits: - if inscrit != winner: - new_context = dict(context) - new_context['acheteur'] = inscrit.user - datatuple.append(( - 'bda-revente-loser', - new_context, - settings.MAIL_DATA['revente']['FROM'], - [inscrit.user.email] - )) - send_mass_custom_mail(datatuple) + # Envoie un mail aux perdants + for inscrit in inscrits: + if inscrit != winner: + new_context = dict(context) + new_context['acheteur'] = inscrit.user + datatuple.append(( + 'bda-revente-loser', + new_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/tests/test_revente.py b/bda/tests/test_revente.py new file mode 100644 index 00000000..8ef7be19 --- /dev/null +++ b/bda/tests/test_revente.py @@ -0,0 +1,69 @@ +from django.contrib.auth.models import User +from django.test import TestCase, Client +from django.utils import timezone + +from datetime import timedelta + +from bda.models import (Tirage, Spectacle, Salle, CategorieSpectacle, + SpectacleRevente, Attribution, Participant) + + +class TestModels(TestCase): + def setUp(self): + self.tirage = Tirage.objects.create( + title="Tirage test", + appear_catalogue=True, + ouverture=timezone.now(), + fermeture=timezone.now() + ) + self.category = CategorieSpectacle.objects.create(name="Category") + self.location = Salle.objects.create(name="here") + self.spectacle_soon = Spectacle.objects.create( + title="foo", date=timezone.now()+timedelta(days=1), + location=self.location, price=0, slots=42, + tirage=self.tirage, listing=False, category=self.category + ) + self.spectacle_later = Spectacle.objects.create( + title="bar", date=timezone.now()+timedelta(days=30), + location=self.location, price=0, slots=42, + tirage=self.tirage, listing=False, category=self.category + ) + + user_buyer = User.objects.create_user( + username="bda_buyer", password="testbuyer" + ) + user_seller = User.objects.create_user( + username="bda_seller", password="testseller" + ) + self.buyer = Participant.objects.create( + user=user_buyer, tirage=self.tirage + ) + self.seller = Participant.objects.create( + user=user_seller, tirage=self.tirage + ) + + self.attr_soon = Attribution.objects.create( + participant=self.seller, spectacle=self.spectacle_soon + ) + self.attr_later = Attribution.objects.create( + participant=self.seller, spectacle=self.spectacle_later + ) + self.revente_soon = SpectacleRevente.objects.create( + seller=self.seller, + attribution=self.attr_soon + ) + self.revente_later = SpectacleRevente.objects.create( + seller=self.seller, + attribution=self.attr_later + ) + + def test_urgent(self): + self.assertTrue(self.revente_soon.is_urgent) + self.assertFalse(self.revente_later.is_urgent) + + def test_tirage(self): + self.revente_soon.confirmed_entry.add(self.buyer) + + self.assertEqual(self.revente_soon.tirage(send_mails=False), + self.buyer) + self.assertIsNone(self.revente_later.tirage(send_mails=False)) From f1bbade002663adff353ba477a6a9889580416b8 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Dec 2017 12:40:50 +0100 Subject: [PATCH 14/49] Better labels for `revente` objects The label for the ReventeModelMultipleChoiceField now depends on a `own` parameter, which determines if we display the seller or the buyer's name. --- bda/forms.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 2929f771..14e91ce2 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -47,8 +47,29 @@ class AttributionModelMultipleChoiceField(forms.ModelMultipleChoiceField): class ReventeModelMultipleChoiceField(forms.ModelMultipleChoiceField): + def __init__(self, *args, own=True, **kwargs): + super().__init__(*args, **kwargs) + self.own = own + def label_from_instance(self, obj): - return str(obj.attribution.spectacle) + label = "{show}{suffix}" + suffix = "" + if self.own: + # C'est notre propre revente : pas besoin de spécifier le vendeur + if obj.soldTo is not None: + suffix = " -- Vendue à {firstname} {lastname}".format( + firstname=obj.soldTo.user.first_name, + lastname=obj.soldTo.user.last_name, + ) + else: + # Ce n'est pas à nous : on ne voit jamais l'acheteur + suffix = " -- Vendue par {firstname} {lastname}".format( + firstname=obj.seller.user.first_name, + lastname=obj.seller.user.last_name, + ) + + return label.format(show=str(obj.attribution.spectacle), + suffix=suffix) class ResellForm(forms.Form): @@ -106,6 +127,7 @@ class InscriptionReventeForm(forms.Form): class ReventeTirageAnnulForm(forms.Form): reventes = ReventeModelMultipleChoiceField( + own=False, label='', queryset=SpectacleRevente.objects.none(), widget=forms.CheckboxSelectMultiple, @@ -116,12 +138,14 @@ class ReventeTirageAnnulForm(forms.Form): super().__init__(*args, **kwargs) self.fields['reventes'].queryset = ( participant.entered.filter(soldTo__isnull=True) - .select_related('attribution__spectacle') + .select_related('attribution__spectacle', + 'seller__user') ) class ReventeTirageForm(forms.Form): reventes = ReventeModelMultipleChoiceField( + own=False, label='', queryset=SpectacleRevente.objects.none(), widget=forms.CheckboxSelectMultiple, From 1783196a9c137d52fcfe033a97c7c09bf2cec140 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Dec 2017 12:41:50 +0100 Subject: [PATCH 15/49] Management view only deals with Revente objects Except for Revente creation, every form is now handled with revente objects, to use the display option in the previous commit. --- bda/forms.py | 34 +++++++++++++------------- bda/templates/bda/revente/manage.html | 16 ++++++------ bda/templates/bda/revente/tirages.html | 4 +-- bda/views.py | 20 +++++++-------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 14e91ce2..90b0359f 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -91,7 +91,8 @@ class ResellForm(forms.Form): class AnnulForm(forms.Form): - attributions = AttributionModelMultipleChoiceField( + reventes = ReventeModelMultipleChoiceField( + own=True, label='', queryset=Attribution.objects.none(), widget=forms.CheckboxSelectMultiple, @@ -99,14 +100,13 @@ class AnnulForm(forms.Form): def __init__(self, participant, *args, **kwargs): super(AnnulForm, self).__init__(*args, **kwargs) - self.fields['attributions'].queryset = ( - participant.attribution_set - .filter(spectacle__date__gte=timezone.now(), - revente__isnull=False, - revente__notif_sent=False, - revente__soldTo__isnull=True) - .select_related('spectacle', 'spectacle__location', - 'participant__user') + self.fields['reventes'].queryset = ( + participant.original_shows + .filter(attribution__spectacle__date__gte=timezone.now(), + notif_sent=False, + soldTo__isnull=True) + .select_related('attribution__spectacle', + 'attribution__spectacle__location') ) @@ -165,18 +165,18 @@ class ReventeTirageForm(forms.Form): class SoldForm(forms.Form): - attributions = AttributionModelMultipleChoiceField( + reventes = ReventeModelMultipleChoiceField( + own=True, label='', queryset=Attribution.objects.none(), widget=forms.CheckboxSelectMultiple) def __init__(self, participant, *args, **kwargs): super(SoldForm, self).__init__(*args, **kwargs) - self.fields['attributions'].queryset = ( - participant.attribution_set - .filter(revente__isnull=False, - revente__soldTo__isnull=False) - .exclude(revente__soldTo=participant) - .select_related('spectacle', 'spectacle__location', - 'participant__user') + self.fields['reventes'].queryset = ( + participant.original_shows + .filter(soldTo__isnull=False) + .exclude(soldTo=participant) + .select_related('attribution__spectacle', + 'attribution__spectacle__location') ) diff --git a/bda/templates/bda/revente/manage.html b/bda/templates/bda/revente/manage.html index 8162d55d..cf0ba80e 100644 --- a/bda/templates/bda/revente/manage.html +++ b/bda/templates/bda/revente/manage.html @@ -4,7 +4,7 @@ {% block realcontent %}

    Gestion des places que je revends

    -{% with resell_attributions=resellform.attributions annul_attributions=annulform.attributions sold_attributions=soldform.attributions %} +{% with resell_attributions=resellform.attributions annul_reventes=annulform.reventes sold_reventes=soldform.reventes %} {% if resellform.attributions %}
    @@ -29,10 +29,10 @@
    {% endif %} -{% if annul_attributions or overdue %} +{% if annul_reventes or overdue %}

    Places en cours de revente

    - {% if annul_attributions %} + {% if annul_reventes %}
    Vous pouvez annuler les places mises en vente il y a moins d'une heure. @@ -42,8 +42,8 @@
      - {% for attrib in annul_attributions %} -
    • {{ attrib.tag }} {{ attrib.choice_label }}
    • + {% for revente in annul_reventes %} +
    • {{ revente.tag }} {{ revente.choice_label }}
    • {% endfor %} {% for attrib in overdue %}
    • @@ -54,7 +54,7 @@
    - {% if annul_attributions %} + {% if annul_reventes %} {% endif %} @@ -62,7 +62,7 @@
    {% endif %} -{% if sold_attributions %} +{% if sold_reventes %}

    Places revendues

    @@ -82,7 +82,7 @@ {% endif %} -{% if not resell_attributions and not annul_attributions and not overdue and not sold_attributions %} +{% if not resell_attributions and not annul_attributions and not overdue and not sold_reventes %}

    Plus de reventes possibles !

    {% endif %} diff --git a/bda/templates/bda/revente/tirages.html b/bda/templates/bda/revente/tirages.html index 91d39c90..b7017806 100644 --- a/bda/templates/bda/revente/tirages.html +++ b/bda/templates/bda/revente/tirages.html @@ -11,7 +11,7 @@
    Vous pouvez vous désinscrire des reventes suivantes tant que le tirage n'a - pas eu lieu + pas eu lieu.
    {% csrf_token %} @@ -34,7 +34,7 @@
    - Vous pouvez vous inscrire aux tirage en cours suivants + Vous pouvez vous inscrire aux tirage en cours suivants.
    {% csrf_token %} diff --git a/bda/views.py b/bda/views.py index 67fa2486..4cb35c52 100644 --- a/bda/views.py +++ b/bda/views.py @@ -401,18 +401,18 @@ def revente_manage(request, tirage_id): elif 'annul' in request.POST: annulform = AnnulForm(participant, request.POST, prefix='annul') if annulform.is_valid(): - attributions = annulform.cleaned_data["attributions"] - for attribution in attributions: - attribution.revente.delete() + reventes = annulform.cleaned_data["reventes"] + for revente in reventes: + revente.delete() # On confirme une vente en transférant la place à la personne qui a # gagné le tirage elif 'transfer' in request.POST: soldform = SoldForm(participant, request.POST, prefix='sold') if soldform.is_valid(): - attributions = soldform.cleaned_data['attributions'] - for attribution in attributions: - attribution.participant = attribution.revente.soldTo - attribution.save() + reventes = soldform.cleaned_data['reventes'] + for reventes in reventes: + revente.attribution.participant = revente.soldTo + revente.attribution.save() # On annule la revente après le tirage au sort (par exemple si # la personne qui a gagné le tirage ne se manifeste pas). La place est @@ -420,9 +420,9 @@ def revente_manage(request, tirage_id): elif 'reinit' in request.POST: soldform = SoldForm(participant, request.POST, prefix='sold') if soldform.is_valid(): - attributions = soldform.cleaned_data['attributions'] - for attribution in attributions: - if attribution.spectacle.date > timezone.now(): + reventes = soldform.cleaned_data['reventes'] + for revente in reventes: + if revente.attribution.spectacle.date > timezone.now(): # On antidate pour envoyer le mail plus vite new_date = (timezone.now() - SpectacleRevente.remorse_time) From 9a8773978c52defaf98dd7fd58babd4961273dd5 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Dec 2017 12:50:20 +0100 Subject: [PATCH 16/49] Use new method in admin --- bda/admin.py | 8 +------- bda/models.py | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index 4f5d821a..2d289b71 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -288,13 +288,7 @@ class SpectacleReventeAdmin(admin.ModelAdmin): count = queryset.count() for revente in queryset.filter( attribution__spectacle__date__gte=timezone.now()): - revente.date = timezone.now() - timedelta(hours=1) - revente.soldTo = None - revente.notif_sent = False - revente.tirage_done = False - if revente.confirmed_entry: - revente.confirmed_entry.clear() - revente.save() + revente.reset(new_date=timezone.now() - timedelta(hours=1)) self.message_user( request, "%d attribution%s %s été réinitialisée%s avec succès." % ( diff --git a/bda/models.py b/bda/models.py index c01fe727..722a3ef7 100644 --- a/bda/models.py +++ b/bda/models.py @@ -300,6 +300,7 @@ class SpectacleRevente(models.Model): self.confirmed_entry.clear() self.soldTo = None self.notif_sent = False + self.notif_time = None self.tirage_done = False self.shotgun = False self.save() From 475f1adec57ae2206d19a5bd49effee9433d2a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 6 Jan 2018 12:23:24 +0100 Subject: [PATCH 17/49] Remove "coding: utf8" line --- bda/admin.py | 2 -- bda/algorithm.py | 2 -- bda/autocomplete_light_registry.py | 2 -- bda/forms.py | 2 -- bda/management/commands/manage_reventes.py | 2 -- bda/management/commands/sendrappels.py | 2 -- bda/models.py | 2 -- bda/urls.py | 2 -- bda/views.py | 2 -- cof/locale/fr/formats.py | 2 -- cof/settings/common.py | 1 - cof/urls.py | 2 -- gestioncof/autocomplete.py | 2 -- gestioncof/autocomplete_light_registry.py | 2 -- gestioncof/csv_views.py | 2 -- gestioncof/decorators.py | 2 -- gestioncof/management/commands/syncmails.py | 1 - gestioncof/petits_cours_forms.py | 2 -- gestioncof/petits_cours_models.py | 2 -- gestioncof/petits_cours_views.py | 2 -- gestioncof/templatetags/utils.py | 2 -- gestioncof/tests.py | 1 - gestioncof/urls.py | 2 -- gestioncof/widgets.py | 2 -- kfet/apps.py | 2 -- kfet/auth/backends.py | 1 - kfet/auth/middleware.py | 1 - kfet/auth/tests.py | 1 - kfet/autocomplete.py | 2 -- kfet/config.py | 2 -- kfet/consumers.py | 2 -- kfet/context_processors.py | 2 -- kfet/decorators.py | 2 -- kfet/forms.py | 2 -- kfet/models.py | 2 -- kfet/routing.py | 2 -- kfet/statistic.py | 2 -- kfet/templatetags/kfet_tags.py | 2 -- kfet/tests/test_config.py | 2 -- kfet/tests/test_statistic.py | 2 -- kfet/urls.py | 2 -- kfet/views.py | 2 -- 42 files changed, 78 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index 60d3c1ba..4736ce2d 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import autocomplete_light from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail diff --git a/bda/algorithm.py b/bda/algorithm.py index 7f18ce18..7d6ab2f0 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py index 6c2f3ea6..774e5c2b 100644 --- a/bda/autocomplete_light_registry.py +++ b/bda/autocomplete_light_registry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/bda/forms.py b/bda/forms.py index c0417d1e..3b0dd5bd 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django import forms from django.forms.models import BaseInlineFormSet from django.utils import timezone diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py index 0302ec4b..f5dee265 100644 --- a/bda/management/commands/manage_reventes.py +++ b/bda/management/commands/manage_reventes.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Gestion en ligne de commande des reventes. """ diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py index 88cf9d5c..8fbdb31c 100644 --- a/bda/management/commands/sendrappels.py +++ b/bda/management/commands/sendrappels.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Gestion en ligne de commande des mails de rappel. """ diff --git a/bda/models.py b/bda/models.py index 41462d70..42c3b3ef 100644 --- a/bda/models.py +++ b/bda/models.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import calendar import random from datetime import timedelta diff --git a/bda/urls.py b/bda/urls.py index 876c84ea..52e74a67 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/bda/views.py b/bda/views.py index 84b6c9d3..7109443a 100644 --- a/bda/views.py +++ b/bda/views.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from collections import defaultdict import random import hashlib diff --git a/cof/locale/fr/formats.py b/cof/locale/fr/formats.py index 710fa6ed..ec63d8cc 100644 --- a/cof/locale/fr/formats.py +++ b/cof/locale/fr/formats.py @@ -1,5 +1,3 @@ -# -*- encoding: utf-8 -*- - """ Formats français. """ diff --git a/cof/settings/common.py b/cof/settings/common.py index a2ea3f5e..4c573d95 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Django common settings for cof project. diff --git a/cof/urls.py b/cof/urls.py index f62d5f01..4599d332 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - """ Fichier principal de configuration des urls du projet GestioCOF """ diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 968398fd..1d60cd78 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from ldap3 import Connection from django import shortcuts diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index 4c62d995..6e04022f 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import autocomplete_light from django.contrib.auth.models import User diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py index c1d82aca..a4f3c028 100644 --- a/gestioncof/csv_views.py +++ b/gestioncof/csv_views.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/gestioncof/decorators.py b/gestioncof/decorators.py index a1263ce3..3875b77d 100644 --- a/gestioncof/decorators.py +++ b/gestioncof/decorators.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.contrib.auth.decorators import user_passes_test diff --git a/gestioncof/management/commands/syncmails.py b/gestioncof/management/commands/syncmails.py index 1d3dddb8..ba61dcf4 100644 --- a/gestioncof/management/commands/syncmails.py +++ b/gestioncof/management/commands/syncmails.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Import des mails de GestioCOF dans la base de donnée """ diff --git a/gestioncof/petits_cours_forms.py b/gestioncof/petits_cours_forms.py index dfb7a263..c0770afc 100644 --- a/gestioncof/petits_cours_forms.py +++ b/gestioncof/petits_cours_forms.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from captcha.fields import ReCaptchaField from django import forms diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index d9ea9668..06199a01 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from functools import reduce from django.db import models diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 087c9cef..5854a927 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import json from datetime import datetime from custommail.shortcuts import render_custom_mail diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 76bc6003..5afd8cfa 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/gestioncof/tests.py b/gestioncof/tests.py index 66043daf..f99b0fcb 100644 --- a/gestioncof/tests.py +++ b/gestioncof/tests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This file demonstrates writing tests using the unittest module. These will pass when you run "manage.py test". diff --git a/gestioncof/urls.py b/gestioncof/urls.py index 57c2e8f2..02814673 100644 --- a/gestioncof/urls.py +++ b/gestioncof/urls.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.conf.urls import url from gestioncof.petits_cours_views import DemandeListView, DemandeDetailView from gestioncof import views, petits_cours_views diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index 758fc4ad..a44e93b0 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import division from __future__ import print_function from __future__ import unicode_literals diff --git a/kfet/apps.py b/kfet/apps.py index 4f114c37..a18dd905 100644 --- a/kfet/apps.py +++ b/kfet/apps.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from __future__ import (absolute_import, division, print_function, unicode_literals) from builtins import * diff --git a/kfet/auth/backends.py b/kfet/auth/backends.py index c6ad21b2..d8ef3001 100644 --- a/kfet/auth/backends.py +++ b/kfet/auth/backends.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.contrib.auth import get_user_model from kfet.models import Account, GenericTeamToken diff --git a/kfet/auth/middleware.py b/kfet/auth/middleware.py index 748ce4dd..388be4fc 100644 --- a/kfet/auth/middleware.py +++ b/kfet/auth/middleware.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.contrib.auth import get_user_model from .backends import AccountBackend diff --git a/kfet/auth/tests.py b/kfet/auth/tests.py index c2f183cd..3a61daa2 100644 --- a/kfet/auth/tests.py +++ b/kfet/auth/tests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from unittest import mock from django.core import signing diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index c4886180..0d1904d6 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from ldap3 import Connection from django.shortcuts import render from django.http import Http404 diff --git a/kfet/config.py b/kfet/config.py index 76da5a79..f248b370 100644 --- a/kfet/config.py +++ b/kfet/config.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.core.exceptions import ValidationError from django.db import models diff --git a/kfet/consumers.py b/kfet/consumers.py index 0f447d2d..a53bbb72 100644 --- a/kfet/consumers.py +++ b/kfet/consumers.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from .utils import DjangoJsonWebsocketConsumer, PermConsumerMixin diff --git a/kfet/context_processors.py b/kfet/context_processors.py index 04feec81..89678f62 100644 --- a/kfet/context_processors.py +++ b/kfet/context_processors.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from kfet.config import kfet_config diff --git a/kfet/decorators.py b/kfet/decorators.py index 0c8a1a76..66c9d71c 100644 --- a/kfet/decorators.py +++ b/kfet/decorators.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.contrib.auth.decorators import user_passes_test diff --git a/kfet/forms.py b/kfet/forms.py index 963e4254..5cfef918 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from datetime import timedelta from decimal import Decimal diff --git a/kfet/models.py b/kfet/models.py index b1e351d5..08ca4490 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.db import models from django.core.urlresolvers import reverse from django.core.validators import RegexValidator diff --git a/kfet/routing.py b/kfet/routing.py index 54de69ae..f1305d4b 100644 --- a/kfet/routing.py +++ b/kfet/routing.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from channels.routing import include, route_class from . import consumers diff --git a/kfet/statistic.py b/kfet/statistic.py index 3f32807e..0aba4dda 100644 --- a/kfet/statistic.py +++ b/kfet/statistic.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from datetime import date, datetime, time, timedelta from dateutil.relativedelta import relativedelta diff --git a/kfet/templatetags/kfet_tags.py b/kfet/templatetags/kfet_tags.py index f5cd3848..68b74738 100644 --- a/kfet/templatetags/kfet_tags.py +++ b/kfet/templatetags/kfet_tags.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import re from django import template diff --git a/kfet/tests/test_config.py b/kfet/tests/test_config.py index 03c9cf3c..43497ca8 100644 --- a/kfet/tests/test_config.py +++ b/kfet/tests/test_config.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from decimal import Decimal from django.test import TestCase diff --git a/kfet/tests/test_statistic.py b/kfet/tests/test_statistic.py index d8db7ec8..93de27a0 100644 --- a/kfet/tests/test_statistic.py +++ b/kfet/tests/test_statistic.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from unittest.mock import patch from django.test import TestCase, Client diff --git a/kfet/urls.py b/kfet/urls.py index f39299a5..96fd4ddf 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from django.conf.urls import include, url from django.contrib.auth.decorators import permission_required diff --git a/kfet/views.py b/kfet/views.py index f1dd6834..5c52637d 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import ast from urllib.parse import urlencode From 57411ab46f9da69f0f8d392f6b08785f878d98a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 6 Jan 2018 12:32:42 +0100 Subject: [PATCH 18/49] Remove __future__ imports --- bda/algorithm.py | 4 ---- bda/autocomplete_light_registry.py | 4 ---- bda/management/commands/manage_reventes.py | 2 -- bda/management/commands/sendrappels.py | 2 -- bda/urls.py | 4 ---- cof/locale/fr/formats.py | 2 -- gestioncof/csv_views.py | 4 ---- gestioncof/templatetags/utils.py | 4 ---- gestioncof/tests.py | 4 ---- gestioncof/widgets.py | 4 ---- kfet/apps.py | 2 -- requirements.txt | 1 - 12 files changed, 37 deletions(-) diff --git a/bda/algorithm.py b/bda/algorithm.py index 7d6ab2f0..f0f48ad9 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.db.models import Max import random diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py index 774e5c2b..7aa43b07 100644 --- a/bda/autocomplete_light_registry.py +++ b/bda/autocomplete_light_registry.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import autocomplete_light from bda.models import Participant, Spectacle diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py index f5dee265..23bb7ae6 100644 --- a/bda/management/commands/manage_reventes.py +++ b/bda/management/commands/manage_reventes.py @@ -2,8 +2,6 @@ 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 diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py index 8fbdb31c..82889f80 100644 --- a/bda/management/commands/sendrappels.py +++ b/bda/management/commands/sendrappels.py @@ -2,8 +2,6 @@ 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 diff --git a/bda/urls.py b/bda/urls.py index 52e74a67..8a27fed0 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.conf.urls import url from gestioncof.decorators import buro_required from bda.views import SpectacleListView diff --git a/cof/locale/fr/formats.py b/cof/locale/fr/formats.py index ec63d8cc..4b47ce3d 100644 --- a/cof/locale/fr/formats.py +++ b/cof/locale/fr/formats.py @@ -2,6 +2,4 @@ Formats français. """ -from __future__ import unicode_literals - DATETIME_FORMAT = r'l j F Y \à H:i' diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py index a4f3c028..733768dc 100644 --- a/gestioncof/csv_views.py +++ b/gestioncof/csv_views.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - import csv from django.http import HttpResponse, HttpResponseForbidden from django.template.defaultfilters import slugify diff --git a/gestioncof/templatetags/utils.py b/gestioncof/templatetags/utils.py index 5afd8cfa..2b732aec 100644 --- a/gestioncof/templatetags/utils.py +++ b/gestioncof/templatetags/utils.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django import template from django.utils.safestring import mark_safe diff --git a/gestioncof/tests.py b/gestioncof/tests.py index f99b0fcb..85673edd 100644 --- a/gestioncof/tests.py +++ b/gestioncof/tests.py @@ -5,10 +5,6 @@ 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 from gestioncof.models import CofProfile, User diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index a44e93b0..134ddd80 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -1,7 +1,3 @@ -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.forms.widgets import Widget from django.forms.utils import flatatt from django.utils.safestring import mark_safe diff --git a/kfet/apps.py b/kfet/apps.py index a18dd905..8d8170e9 100644 --- a/kfet/apps.py +++ b/kfet/apps.py @@ -1,5 +1,3 @@ -from __future__ import (absolute_import, division, - print_function, unicode_literals) from builtins import * from django.apps import AppConfig diff --git a/requirements.txt b/requirements.txt index 1591656d..c9c6c4c0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,6 @@ asgiref==1.1.1 daphne==1.3.0 asgi-redis==1.3.0 statistics==1.0.3.5 -future==0.15.2 django-widget-tweaks==1.4.1 git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_custommail ldap3 From 97eed06b6fdd1e808e5add5200a52ae8429cd8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 6 Jan 2018 12:33:30 +0100 Subject: [PATCH 19/49] Remove builtins imports --- kfet/apps.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kfet/apps.py b/kfet/apps.py index 8d8170e9..7a6c97a2 100644 --- a/kfet/apps.py +++ b/kfet/apps.py @@ -1,7 +1,6 @@ -from builtins import * - from django.apps import AppConfig + class KFetConfig(AppConfig): name = 'kfet' verbose_name = "Application K-Fêt" From 62d8c2ffaf765e1af33767eb6aa8e85ad4cc019a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 6 Jan 2018 12:37:00 +0100 Subject: [PATCH 20/49] remove @py2_unicode_compat + six --- kfet/models.py | 8 +++----- requirements.txt | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/kfet/models.py b/kfet/models.py index 08ca4490..4d30d719 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -1,11 +1,11 @@ +from functools import reduce + from django.db import models from django.core.urlresolvers import reverse from django.core.validators import RegexValidator from django.contrib.auth.models import User from gestioncof.models import CofProfile -from django.utils.six.moves import reduce from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from django.db import transaction from django.db.models import F @@ -370,7 +370,7 @@ class CheckoutTransfer(models.Model): amount = models.DecimalField( max_digits = 6, decimal_places = 2) -@python_2_unicode_compatible + class CheckoutStatement(models.Model): by = models.ForeignKey( Account, on_delete = models.PROTECT, @@ -439,7 +439,6 @@ class CheckoutStatement(models.Model): super(CheckoutStatement, self).save(*args, **kwargs) -@python_2_unicode_compatible class ArticleCategory(models.Model): name = models.CharField("nom", max_length=45) has_addcost = models.BooleanField("majorée", default=True, @@ -452,7 +451,6 @@ class ArticleCategory(models.Model): return self.name -@python_2_unicode_compatible class Article(models.Model): name = models.CharField("nom", max_length = 45) is_sold = models.BooleanField("en vente", default = True) diff --git a/requirements.txt b/requirements.txt index c9c6c4c0..914eca1c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,6 @@ django-recaptcha==1.0.5 django-redis-cache==1.7.1 psycopg2 Pillow==3.3.0 -six==1.10.0 unicodecsv==0.14.1 icalendar==3.10 django-bootstrap-form==3.2.1 From 91119f68bc5deef627baa47ec7fb80e56c0bb514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 10 Jan 2018 17:34:41 +0100 Subject: [PATCH 21/49] =?UTF-8?q?Ne=20pas=20oublier=20avant=20de=20passer?= =?UTF-8?q?=20en=20prod=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO_PROD.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 TODO_PROD.md diff --git a/TODO_PROD.md b/TODO_PROD.md new file mode 100644 index 00000000..1a7d0736 --- /dev/null +++ b/TODO_PROD.md @@ -0,0 +1 @@ +- Changer les urls dans les mails "bda-revente" et "bda-shotgun" From 52fd49616dab6515ab6e113ccb405878c59f18dd Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 10 Jan 2018 20:14:27 +0100 Subject: [PATCH 22/49] Fix model test --- bda/tests/test_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bda/tests/test_models.py b/bda/tests/test_models.py index d9242b3f..95ce8646 100644 --- a/bda/tests/test_models.py +++ b/bda/tests/test_models.py @@ -67,7 +67,7 @@ class SpectacleReventeTests(TestCase): revente = self.rev wanted_by = [self.p1, self.p2, self.p3] - revente.answered_mail = wanted_by + revente.confirmed_entry = wanted_by with mock.patch('bda.models.random.choice') as mc: # Set winner to self.p1. From 42e762bc4a07cde8eee2a9e12ef9e51ce1b75322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Tue, 16 Jan 2018 16:22:52 +0100 Subject: [PATCH 23/49] Py3 allows to shorten super() --- bda/admin.py | 2 +- bda/forms.py | 8 ++++---- bda/views.py | 2 +- gestioncof/admin.py | 4 ++-- gestioncof/forms.py | 28 +++++++++++++------------- gestioncof/petits_cours_forms.py | 4 ++-- gestioncof/petits_cours_views.py | 2 +- gestioncof/widgets.py | 2 +- kfet/forms.py | 20 +++++++++---------- kfet/models.py | 8 ++++---- kfet/views.py | 34 ++++++++++++++++---------------- 11 files changed, 57 insertions(+), 57 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index 0e796f57..5511cf85 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -164,7 +164,7 @@ class AttributionAdminForm(forms.ModelForm): ) def clean(self): - cleaned_data = super(AttributionAdminForm, self).clean() + cleaned_data = super().clean() participant = cleaned_data.get("participant") spectacle = cleaned_data.get("spectacle") if participant and spectacle: diff --git a/bda/forms.py b/bda/forms.py index 3b0dd5bd..a363c36e 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -52,7 +52,7 @@ class ResellForm(forms.Form): required=False) def __init__(self, participant, *args, **kwargs): - super(ResellForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['attributions'].queryset = ( participant.attribution_set .filter(spectacle__date__gte=timezone.now()) @@ -70,7 +70,7 @@ class AnnulForm(forms.Form): required=False) def __init__(self, participant, *args, **kwargs): - super(AnnulForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['attributions'].queryset = ( participant.attribution_set .filter(spectacle__date__gte=timezone.now(), @@ -89,7 +89,7 @@ class InscriptionReventeForm(forms.Form): required=False) def __init__(self, tirage, *args, **kwargs): - super(InscriptionReventeForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['spectacles'].queryset = ( tirage.spectacle_set .select_related('location') @@ -104,7 +104,7 @@ class SoldForm(forms.Form): widget=forms.CheckboxSelectMultiple) def __init__(self, participant, *args, **kwargs): - super(SoldForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['attributions'].queryset = ( participant.attribution_set .filter(revente__isnull=False, diff --git a/bda/views.py b/bda/views.py index 4d18a043..dace3c51 100644 --- a/bda/views.py +++ b/bda/views.py @@ -628,7 +628,7 @@ class SpectacleListView(ListView): return categories def get_context_data(self, **kwargs): - context = super(SpectacleListView, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) context['tirage_id'] = self.tirage.id context['tirage_name'] = self.tirage.title return context diff --git a/gestioncof/admin.py b/gestioncof/admin.py index 51969822..54a6a5a0 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -181,7 +181,7 @@ class UserProfileAdmin(UserAdmin): def get_fieldsets(self, request, user=None): if not request.user.is_superuser: return self.staff_fieldsets - return super(UserProfileAdmin, self).get_fieldsets(request, user) + return super().get_fieldsets(request, user) def save_model(self, request, user, form, change): cof_group, created = Group.objects.get_or_create(name='COF') @@ -267,7 +267,7 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin): class ClubAdminForm(forms.ModelForm): def clean(self): - cleaned_data = super(ClubAdminForm, self).clean() + cleaned_data = super().clean() respos = cleaned_data.get('respos') members = cleaned_data.get('membres') for respo in respos.all(): diff --git a/gestioncof/forms.py b/gestioncof/forms.py index 2124b7c8..0d1db499 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -18,7 +18,7 @@ class EventForm(forms.Form): event = kwargs.pop("event") self.event = event current_choices = kwargs.pop("current_choices", None) - super(EventForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) choices = {} if current_choices: for choice in current_choices.all(): @@ -60,7 +60,7 @@ class SurveyForm(forms.Form): def __init__(self, *args, **kwargs): survey = kwargs.pop("survey") current_answers = kwargs.pop("current_answers", None) - super(SurveyForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) answers = {} if current_answers: for answer in current_answers.all(): @@ -100,7 +100,7 @@ class SurveyForm(forms.Form): class SurveyStatusFilterForm(forms.Form): def __init__(self, *args, **kwargs): survey = kwargs.pop("survey") - super(SurveyStatusFilterForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) for question in survey.questions.all(): for answer in question.answers.all(): name = "question_%d_answer_%d" % (question.id, answer.id) @@ -129,7 +129,7 @@ class SurveyStatusFilterForm(forms.Form): class EventStatusFilterForm(forms.Form): def __init__(self, *args, **kwargs): event = kwargs.pop("event") - super(EventStatusFilterForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) for option in event.options.all(): for choice in option.choices.all(): name = "option_%d_choice_%d" % (option.id, choice.id) @@ -175,12 +175,12 @@ class UserProfileForm(forms.ModelForm): last_name = forms.CharField(label=_('Nom'), max_length=30) def __init__(self, *args, **kw): - super(UserProfileForm, self).__init__(*args, **kw) + super().__init__(*args, **kw) self.fields['first_name'].initial = self.instance.user.first_name self.fields['last_name'].initial = self.instance.user.last_name def save(self, *args, **kw): - super(UserProfileForm, self).save(*args, **kw) + super().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() @@ -193,7 +193,7 @@ class UserProfileForm(forms.ModelForm): class RegistrationUserForm(forms.ModelForm): def __init__(self, *args, **kw): - super(RegistrationUserForm, self).__init__(*args, **kw) + super().__init__(*args, **kw) self.fields['username'].help_text = "" class Meta: @@ -219,8 +219,7 @@ class RegistrationPassUserForm(RegistrationUserForm): return pass2 def save(self, commit=True, *args, **kwargs): - user = super(RegistrationPassUserForm, self).save(commit, *args, - **kwargs) + user = super().save(commit, *args, **kwargs) user.set_password(self.cleaned_data['password2']) if commit: user.save() @@ -229,7 +228,7 @@ class RegistrationPassUserForm(RegistrationUserForm): class RegistrationProfileForm(forms.ModelForm): def __init__(self, *args, **kw): - super(RegistrationProfileForm, self).__init__(*args, **kw) + super().__init__(*args, **kw) self.fields['mailing_cof'].initial = True self.fields['mailing_bda'].initial = True self.fields['mailing_bda_revente'].initial = True @@ -274,7 +273,7 @@ class AdminEventForm(forms.Form): kwargs["initial"] = {"status": "wait"} else: kwargs["initial"] = {"status": "no"} - super(AdminEventForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) choices = {} for choice in current_choices: if choice.event_option.id not in choices: @@ -337,14 +336,15 @@ class BaseEventRegistrationFormset(BaseFormSet): self.events = kwargs.pop('events') self.current_registrations = kwargs.pop('current_registrations', None) self.extra = len(self.events) - super(BaseEventRegistrationFormset, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _construct_form(self, index, **kwargs): kwargs['event'] = self.events[index] if self.current_registrations is not None: kwargs['current_registration'] = self.current_registrations[index] - return super(BaseEventRegistrationFormset, self)._construct_form( - index, **kwargs) + return super()._construct_form(index, **kwargs) + + EventFormset = formset_factory(AdminEventForm, BaseEventRegistrationFormset) diff --git a/gestioncof/petits_cours_forms.py b/gestioncof/petits_cours_forms.py index c0770afc..e8f067bf 100644 --- a/gestioncof/petits_cours_forms.py +++ b/gestioncof/petits_cours_forms.py @@ -10,7 +10,7 @@ from gestioncof.petits_cours_models import PetitCoursDemande, PetitCoursAbility class BaseMatieresFormSet(BaseInlineFormSet): def clean(self): - super(BaseMatieresFormSet, self).clean() + super().clean() if any(self.errors): # Don't bother validating the formset unless each form is # valid on its own @@ -34,7 +34,7 @@ class DemandeForm(ModelForm): captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'}) def __init__(self, *args, **kwargs): - super(DemandeForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['matieres'].help_text = '' class Meta: diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index ec3d1a58..6b8c8610 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -42,7 +42,7 @@ class DemandeDetailView(DetailView): context_object_name = "demande" def get_context_data(self, **kwargs): - context = super(DemandeDetailView, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) obj = self.object context['attributions'] = obj.petitcoursattribution_set.all() return context diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index 134ddd80..1741cfec 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe class TriStateCheckbox(Widget): def __init__(self, attrs=None, choices=()): - super(TriStateCheckbox, self).__init__(attrs) + super().__init__(attrs) # choices can be any iterable, but we may need to render this widget # multiple times. Thus, collapse it into a list so it can be consumed # more than once. diff --git a/kfet/forms.py b/kfet/forms.py index 5cfef918..417a51a7 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -42,7 +42,7 @@ class AccountForm(forms.ModelForm): # Surcharge pour passer data à Account.save() def save(self, data = {}, *args, **kwargs): - obj = super(AccountForm, self).save(commit = False, *args, **kwargs) + obj = super().save(commit = False, *args, **kwargs) obj.save(data = data) return obj @@ -91,7 +91,7 @@ class AccountPwdForm(forms.Form): raise ValidationError("Mot de passe trop court") if pwd1 != pwd2: raise ValidationError("Les mots de passes sont différents") - super(AccountPwdForm, self).clean() + super().clean() class CofForm(forms.ModelForm): def clean_is_cof(self): @@ -195,7 +195,7 @@ class CheckoutStatementCreateForm(forms.ModelForm): or self.cleaned_data['balance_200'] is None or self.cleaned_data['balance_500'] is None): raise ValidationError("Y'a un problème. Si tu comptes la caisse, mets au moins des 0 stp (et t'as pas idée de comment c'est long de vérifier que t'as mis des valeurs de partout...)") - super(CheckoutStatementCreateForm, self).clean() + super().clean() class CheckoutStatementUpdateForm(forms.ModelForm): class Meta: @@ -236,7 +236,7 @@ class ArticleForm(forms.ModelForm): required = False) def __init__(self, *args, **kwargs): - super(ArticleForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.instance.pk: self.initial['suppliers'] = self.instance.suppliers.values_list('pk', flat=True) @@ -250,7 +250,7 @@ class ArticleForm(forms.ModelForm): category, _ = ArticleCategory.objects.get_or_create(name=category_new) self.cleaned_data['category'] = category - super(ArticleForm, self).clean() + super().clean() class Meta: model = Article @@ -321,7 +321,7 @@ class KPsulOperationForm(forms.ModelForm): } def clean(self): - super(KPsulOperationForm, self).clean() + super().clean() type_ope = self.cleaned_data.get('type') amount = self.cleaned_data.get('amount') article = self.cleaned_data.get('article') @@ -364,7 +364,7 @@ class AddcostForm(forms.Form): raise ValidationError('Compte invalide') else: self.cleaned_data['amount'] = 0 - super(AddcostForm, self).clean() + super().clean() # ----- @@ -462,7 +462,7 @@ class InventoryArticleForm(forms.Form): stock_new = forms.IntegerField(required=False) def __init__(self, *args, **kwargs): - super(InventoryArticleForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if 'initial' in kwargs: self.name = kwargs['initial']['name'] self.stock_old = kwargs['initial']['stock_old'] @@ -484,7 +484,7 @@ class OrderArticleForm(forms.Form): quantity_ordered = forms.IntegerField(required=False) def __init__(self, *args, **kwargs): - super(OrderArticleForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if 'initial' in kwargs: self.name = kwargs['initial']['name'] self.stock = kwargs['initial']['stock'] @@ -514,7 +514,7 @@ class OrderArticleToInventoryForm(forms.Form): quantity_received = forms.IntegerField() def __init__(self, *args, **kwargs): - super(OrderArticleToInventoryForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if 'initial' in kwargs: self.name = kwargs['initial']['name'] self.category = kwargs['initial']['category'] diff --git a/kfet/models.py b/kfet/models.py index e5aed2b7..5cd4b757 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -255,7 +255,7 @@ class Account(models.Model): cof.save() if data: self.cofprofile = cof - super(Account, self).save(*args, **kwargs) + super().save(*args, **kwargs) def change_pwd(self, clear_password): from .auth.utils import hash_password @@ -423,7 +423,7 @@ class CheckoutStatement(models.Model): self.balance_new + self.amount_taken - self.balance_old) with transaction.atomic(): Checkout.objects.filter(pk=checkout_id).update(balance=self.balance_new) - super(CheckoutStatement, self).save(*args, **kwargs) + super().save(*args, **kwargs) else: self.amount_error = ( self.balance_new + self.amount_taken - self.balance_old) @@ -437,7 +437,7 @@ class CheckoutStatement(models.Model): and last_statement.balance_new != self.balance_new): Checkout.objects.filter(pk=self.checkout_id).update( balance=F('balance') - last_statement.balance_new + self.balance_new) - super(CheckoutStatement, self).save(*args, **kwargs) + super().save(*args, **kwargs) class ArticleCategory(models.Model): @@ -538,7 +538,7 @@ class InventoryArticle(models.Model): # d'erreur if not self.inventory.order: self.stock_error = self.stock_new - self.stock_old - super(InventoryArticle, self).save(*args, **kwargs) + super().save(*args, **kwargs) class Supplier(models.Model): diff --git a/kfet/views.py b/kfet/views.py index ef1885b3..df25c95e 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -493,7 +493,7 @@ class AccountNegativeList(ListView): context_object_name = 'negatives' def get_context_data(self, **kwargs): - context = super(AccountNegativeList, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) real_balances = (neg.account.real_balance for neg in self.object_list) context['negatives_sum'] = sum(real_balances) return context @@ -536,7 +536,7 @@ class CheckoutCreate(SuccessMessageMixin, CreateView): balance_new = checkout.balance, amount_taken = 0) - return super(CheckoutCreate, self).form_valid(form) + return super().form_valid(form) # Checkout - Read @@ -546,7 +546,7 @@ class CheckoutRead(DetailView): context_object_name = 'checkout' def get_context_data(self, **kwargs): - context = super(CheckoutRead, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) context['statements'] = context['checkout'].statements.order_by('-at') return context @@ -565,7 +565,7 @@ class CheckoutUpdate(SuccessMessageMixin, UpdateView): form.add_error(None, 'Permission refusée') return self.form_invalid(form) # Updating - return super(CheckoutUpdate, self).form_valid(form) + return super().form_valid(form) # ----- # Checkout Statement views @@ -617,7 +617,7 @@ class CheckoutStatementCreate(SuccessMessageMixin, CreateView): at = self.object.at) def get_context_data(self, **kwargs): - context = super(CheckoutStatementCreate, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) checkout = Checkout.objects.get(pk=self.kwargs['pk_checkout']) context['checkout'] = checkout return context @@ -633,7 +633,7 @@ class CheckoutStatementCreate(SuccessMessageMixin, CreateView): form.instance.balance_new = getAmountBalance(form.cleaned_data) form.instance.checkout_id = self.kwargs['pk_checkout'] form.instance.by = self.request.user.profile.account_kfet - return super(CheckoutStatementCreate, self).form_valid(form) + return super().form_valid(form) class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView): model = CheckoutStatement @@ -645,7 +645,7 @@ class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView): return reverse_lazy('kfet.checkout.read', kwargs={'pk':self.kwargs['pk_checkout']}) def get_context_data(self, **kwargs): - context = super(CheckoutStatementUpdate, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) checkout = Checkout.objects.get(pk=self.kwargs['pk_checkout']) context['checkout'] = checkout return context @@ -657,7 +657,7 @@ class CheckoutStatementUpdate(SuccessMessageMixin, UpdateView): return self.form_invalid(form) # Updating form.instance.amount_taken = getAmountTaken(form.instance) - return super(CheckoutStatementUpdate, self).form_valid(form) + return super().form_valid(form) # ----- # Category views @@ -689,7 +689,7 @@ class CategoryUpdate(SuccessMessageMixin, UpdateView): return self.form_invalid(form) # Updating - return super(CategoryUpdate, self).form_valid(form) + return super().form_valid(form) # ----- # Article views @@ -756,7 +756,7 @@ class ArticleCreate(SuccessMessageMixin, CreateView): ) # Creating - return super(ArticleCreate, self).form_valid(form) + return super().form_valid(form) # Article - Read @@ -766,7 +766,7 @@ class ArticleRead(DetailView): context_object_name = 'article' def get_context_data(self, **kwargs): - context = super(ArticleRead, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) inventoryarts = (InventoryArticle.objects .filter(article=self.object) .select_related('inventory') @@ -818,7 +818,7 @@ class ArticleUpdate(SuccessMessageMixin, UpdateView): article=article, supplier=supplier) # Updating - return super(ArticleUpdate, self).form_valid(form) + return super().form_valid(form) # ----- @@ -1709,7 +1709,7 @@ class InventoryRead(DetailView): context_object_name = 'inventory' def get_context_data(self, **kwargs): - context = super(InventoryRead, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) inventoryarticles = (InventoryArticle.objects .select_related('article', 'article__category') .filter(inventory = self.object) @@ -1727,7 +1727,7 @@ class OrderList(ListView): context_object_name = 'orders' def get_context_data(self, **kwargs): - context = super(OrderList, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) context['suppliers'] = Supplier.objects.order_by('name') return context @@ -1856,7 +1856,7 @@ class OrderRead(DetailView): context_object_name = 'order' def get_context_data(self, **kwargs): - context = super(OrderRead, self).get_context_data(**kwargs) + context = super().get_context_data(**kwargs) orderarticles = (OrderArticle.objects .select_related('article', 'article__category') .filter(order=self.object) @@ -2010,7 +2010,7 @@ class SupplierUpdate(SuccessMessageMixin, UpdateView): form.add_error(None, 'Permission refusée') return self.form_invalid(form) # Updating - return super(SupplierUpdate, self).form_valid(form) + return super().form_valid(form) # ========== @@ -2274,7 +2274,7 @@ class AccountStatBalance(PkUrlMixin, JSONDetailView): @method_decorator(login_required) def dispatch(self, *args, **kwargs): - return super(AccountStatBalance, self).dispatch(*args, **kwargs) + return super().dispatch(*args, **kwargs) # ------------------------ From cc27e4d96427c0cf69d6b58f7b68109d08856c4f Mon Sep 17 00:00:00 2001 From: Qwann Date: Thu, 22 Mar 2018 15:25:03 +0100 Subject: [PATCH 24/49] show not sold article in a different list --- kfet/templates/kfet/article.html | 46 ++++++++++++++++++++++++++++++-- kfet/views.py | 8 ++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/kfet/templates/kfet/article.html b/kfet/templates/kfet/article.html index 7966e797..8cec4279 100644 --- a/kfet/templates/kfet/article.html +++ b/kfet/templates/kfet/article.html @@ -7,8 +7,11 @@ @@ -25,6 +28,7 @@ {% endblock %} {% block main %} +

    Article{{ articles|length|pluralize}} en vente

    @@ -60,6 +64,44 @@
    + +

    Articles non vendus

    +

    Article{{ not_sold_articles|length|pluralize }} non vendu{{ nots_sold_article|length|pluralize }}

    +
    + + + + + + + + + + + + + {% for article in not_sold_articles %} + {% ifchanged article.category %} + + + + {% endifchanged %} + + + + + + + + + {% endfor %} + +
    NomPrixStockEn venteAffichéDernier inventaire
    {{ article.category.name }}
    + + {{ article.name }} + + {{ article.price }}€{{ article.stock }}{{ article.is_sold | yesno:"En vente,Non vendu"}}{{ article.hidden | yesno:"Caché,Affiché" }}{{ article.inventory.0.at }}
    +
    {% endblock %} diff --git a/kfet/views.py b/kfet/views.py index 2b69684d..63bd280c 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -706,6 +706,14 @@ class ArticleList(ListView): ) template_name = 'kfet/article.html' context_object_name = 'articles' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + articles = context[self.context_object_name] + context['nb_articles'] = len(articles) + context[self.context_object_name] = articles.filter(is_sold=True) + context['not_sold_articles'] = articles.filter(is_sold=False) + return context # Article - Create From 71b4e6253da3abc8126b433f86ca54fe47081693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 7 Apr 2018 13:42:19 +0200 Subject: [PATCH 25/49] Merge branch 'master' into aureplop/cof-tests_calendar --- kfet/templates/kfet/account.html | 2 +- kfet/templates/kfet/account_negative.html | 2 +- kfet/templates/kfet/article.html | 2 +- kfet/templates/kfet/article_inventories_snippet.html | 2 +- kfet/templates/kfet/article_suppliers_snippet.html | 2 +- kfet/templates/kfet/category.html | 2 +- kfet/templates/kfet/checkout.html | 2 +- kfet/templates/kfet/checkout_read.html | 2 +- kfet/templates/kfet/inventory.html | 2 +- kfet/templates/kfet/inventory_read.html | 2 +- kfet/templates/kfet/order.html | 2 +- kfet/templates/kfet/order_create.html | 2 +- kfet/templates/kfet/order_read.html | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/kfet/templates/kfet/account.html b/kfet/templates/kfet/account.html index a1a1f6bb..9b63c1da 100644 --- a/kfet/templates/kfet/account.html +++ b/kfet/templates/kfet/account.html @@ -39,7 +39,7 @@
    diff --git a/kfet/templates/kfet/account_negative.html b/kfet/templates/kfet/account_negative.html index b67b94fc..fa8b508d 100644 --- a/kfet/templates/kfet/account_negative.html +++ b/kfet/templates/kfet/account_negative.html @@ -37,7 +37,7 @@
    diff --git a/kfet/templates/kfet/article.html b/kfet/templates/kfet/article.html index caf70cfa..87a8b76a 100644 --- a/kfet/templates/kfet/article.html +++ b/kfet/templates/kfet/article.html @@ -28,7 +28,7 @@
    diff --git a/kfet/templates/kfet/article_inventories_snippet.html b/kfet/templates/kfet/article_inventories_snippet.html index df5c8dea..6a368ab1 100644 --- a/kfet/templates/kfet/article_inventories_snippet.html +++ b/kfet/templates/kfet/article_inventories_snippet.html @@ -1,6 +1,6 @@
    diff --git a/kfet/templates/kfet/article_suppliers_snippet.html b/kfet/templates/kfet/article_suppliers_snippet.html index 84922035..f82a313d 100644 --- a/kfet/templates/kfet/article_suppliers_snippet.html +++ b/kfet/templates/kfet/article_suppliers_snippet.html @@ -1,6 +1,6 @@
    diff --git a/kfet/templates/kfet/category.html b/kfet/templates/kfet/category.html index a31cc3cf..0a8b58be 100644 --- a/kfet/templates/kfet/category.html +++ b/kfet/templates/kfet/category.html @@ -19,7 +19,7 @@
    diff --git a/kfet/templates/kfet/checkout.html b/kfet/templates/kfet/checkout.html index c2c5e4bc..96ce0577 100644 --- a/kfet/templates/kfet/checkout.html +++ b/kfet/templates/kfet/checkout.html @@ -26,7 +26,7 @@
    diff --git a/kfet/templates/kfet/checkout_read.html b/kfet/templates/kfet/checkout_read.html index 37a6e173..acfd4462 100644 --- a/kfet/templates/kfet/checkout_read.html +++ b/kfet/templates/kfet/checkout_read.html @@ -16,7 +16,7 @@ {% else %}
    diff --git a/kfet/templates/kfet/inventory.html b/kfet/templates/kfet/inventory.html index f05dc32a..bee373bc 100644 --- a/kfet/templates/kfet/inventory.html +++ b/kfet/templates/kfet/inventory.html @@ -19,7 +19,7 @@
    diff --git a/kfet/templates/kfet/inventory_read.html b/kfet/templates/kfet/inventory_read.html index 1edc21e0..964e81b0 100644 --- a/kfet/templates/kfet/inventory_read.html +++ b/kfet/templates/kfet/inventory_read.html @@ -29,7 +29,7 @@
    diff --git a/kfet/templates/kfet/order.html b/kfet/templates/kfet/order.html index 0e4ed868..37391b87 100644 --- a/kfet/templates/kfet/order.html +++ b/kfet/templates/kfet/order.html @@ -57,7 +57,7 @@
    diff --git a/kfet/templates/kfet/order_create.html b/kfet/templates/kfet/order_create.html index e2e7c4cd..7cb4d1cb 100644 --- a/kfet/templates/kfet/order_create.html +++ b/kfet/templates/kfet/order_create.html @@ -13,7 +13,7 @@
    diff --git a/kfet/templates/kfet/order_read.html b/kfet/templates/kfet/order_read.html index 9241c394..41abc381 100644 --- a/kfet/templates/kfet/order_read.html +++ b/kfet/templates/kfet/order_read.html @@ -44,7 +44,7 @@
    From 158b19778b19daeba35413027ba30b518d1110a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 7 Apr 2018 14:20:41 +0200 Subject: [PATCH 26/49] also sort the unsold table --- kfet/templates/kfet/article.html | 61 +++++++++++++++++++------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/kfet/templates/kfet/article.html b/kfet/templates/kfet/article.html index 002abadd..b1f173c6 100644 --- a/kfet/templates/kfet/article.html +++ b/kfet/templates/kfet/article.html @@ -79,38 +79,49 @@

    Articles non vendus

    Article{{ not_sold_articles|length|pluralize }} non vendu{{ nots_sold_article|length|pluralize }}

    -
    +
    - - - + + + - - {% for article in not_sold_articles %} - {% ifchanged article.category %} - - - - {% endifchanged %} - - - - - - - - - {% endfor %} - + {% regroup not_sold_articles by category as not_sold_category_list %} + + {% for category in not_sold_category_list %} + + + + + + + {% for article in category.list %} + + + + + + + {% with last_inventory=article.inventory.0 %} + + {% endwith %} + + {% endfor %} + + {% endfor %}
    Nom Prix StockEn venteAffichéDernier inventaireEn venteAffichéDernier inventaire
    {{ article.category.name }}
    - - {{ article.name }} - - {{ article.price }}€{{ article.stock }}{{ article.is_sold | yesno:"En vente,Non vendu"}}{{ article.hidden | yesno:"Caché,Affiché" }}{{ article.inventory.0.at }}
    {{ category.grouper }}
    + + {{ article.name }} + + {{ article.price }}€{{ article.stock }}{{ article.is_sold | yesno:"En vente,Non vendu"}}{{ article.hidden | yesno:"Caché,Affiché" }} + {{ last_inventory.at|date:'d/m/Y H:i' }} +
    From 53a4c78903d6b09611aaa9eb10ee9d36a05d8cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 7 Apr 2018 14:21:07 +0200 Subject: [PATCH 27/49] Remove duplicate line --- kfet/templates/kfet/article.html | 1 - 1 file changed, 1 deletion(-) diff --git a/kfet/templates/kfet/article.html b/kfet/templates/kfet/article.html index b1f173c6..6b48ddbb 100644 --- a/kfet/templates/kfet/article.html +++ b/kfet/templates/kfet/article.html @@ -76,7 +76,6 @@
    -

    Articles non vendus

    Article{{ not_sold_articles|length|pluralize }} non vendu{{ nots_sold_article|length|pluralize }}

    Date: Sun, 8 Apr 2018 22:32:59 +0200 Subject: [PATCH 28/49] Bump django-cors-headers --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 36370bdb..5ad482a5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,7 @@ channels==1.1.5 python-dateutil wagtail==1.10.* wagtailmenus==2.2.* -django-cors-headers==2.1.0 +django-cors-headers==2.2.0 # Production tools wheel From a7cd1e04cd3f93d6d421762b114cfef3dceb4244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 8 Apr 2018 22:33:19 +0200 Subject: [PATCH 29/49] prefer CORS_ORIGIN_WHITELIST to CORS_ORIGIN_REGEX_WHITELIST --- cof/settings/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cof/settings/common.py b/cof/settings/common.py index 00e03869..8ec003ad 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -210,9 +210,11 @@ AUTHENTICATION_BACKENDS = ( RECAPTCHA_USE_SSL = True -CORS_ORIGIN_REGEX_WHITELIST = ( +CORS_ORIGIN_WHITELIST = ( 'bda.ens.fr', + 'www.bda.ens.fr' 'cof.ens.fr', + 'www.cof.ens.fr', ) # Cache settings From 6168045c3aaed467d5135fa158ca4e1f311e7049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 9 Apr 2018 22:43:25 +0200 Subject: [PATCH 30/49] bda: swap double/autoquit descriptions --- bda/migrations/0012_swap_double_choice.py | 53 +++++++++++++++++++++++ bda/models.py | 4 +- 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 bda/migrations/0012_swap_double_choice.py diff --git a/bda/migrations/0012_swap_double_choice.py b/bda/migrations/0012_swap_double_choice.py new file mode 100644 index 00000000..56f3e739 --- /dev/null +++ b/bda/migrations/0012_swap_double_choice.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +def swap_double_choice(apps, schema_editor): + choices = apps.get_model("bda", "ChoixSpectacle").objects + + choices.filter(double_choice="double").update(double_choice="tmp") + choices.filter(double_choice="autoquit").update(double_choice="double") + choices.filter(double_choice="tmp").update(double_choice="autoquit") + + +class Migration(migrations.Migration): + + dependencies = [ + ('bda', '0011_tirage_appear_catalogue'), + ] + + operations = [ + # Temporarily allow an extra "tmp" value for the `double_choice` field + migrations.AlterField( + model_name='choixspectacle', + name='double_choice', + field=models.CharField( + verbose_name='Nombre de places', + max_length=10, + default='1', + choices=[ + ('tmp', 'tmp'), + ('1', '1 place'), + ('double', '2 places si possible, 1 sinon'), + ('autoquit', '2 places sinon rien') + ] + ), + ), + migrations.RunPython(swap_double_choice, migrations.RunPython.noop), + migrations.AlterField( + model_name='choixspectacle', + name='double_choice', + field=models.CharField( + verbose_name='Nombre de places', + max_length=10, + default='1', + choices=[ + ('1', '1 place'), + ('double', '2 places si possible, 1 sinon'), + ('autoquit', '2 places sinon rien') + ] + ), + ), + ] diff --git a/bda/models.py b/bda/models.py index 41462d70..63e08221 100644 --- a/bda/models.py +++ b/bda/models.py @@ -170,8 +170,8 @@ class Participant(models.Model): DOUBLE_CHOICES = ( ("1", "1 place"), - ("autoquit", "2 places si possible, 1 sinon"), - ("double", "2 places sinon rien"), + ("double", "2 places si possible, 1 sinon"), + ("autoquit", "2 places sinon rien"), ) From dd9a81d891df9503fc82a32188ba35c2da00a71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 14 Apr 2018 14:00:37 +0200 Subject: [PATCH 31/49] Update install instructions --- README.md | 106 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index b9d736ae..939d8ac7 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,69 @@ ## Installation +Il est possible d'installer vargant sur votre machine de deux façons différentes : + +- L'installation manuelle (**recommandée** sous linux et OSX), plus légère +- L'installation via vagrant qui fonctionne aussi sous windows mais un peu plus lourde + +### Installation manuelle + +Il est fortement conseillé d'utiliser un environnement virtuel pour Python. + +Il vous faudra installer pip, les librairies de développement de python ainsi +que sqlite3, un moteur de base de données léger et simple d'utilisation. Sous +Debian et dérivées (Ubuntu, ...) : + + sudo apt-get install python3-pip python3-dev python3-venv sqlite3 + +Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; +fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF +(le dossier où se trouve ce README), et créez-le maintenant : + + virtualenv -p python3 venv + +Pour l'activer, il faut taper + + . venv/bin/activate + +depuis le même dossier. + +Vous pouvez maintenant installer les dépendances Python depuis le fichier +`requirements-devel.txt` : + + pip install -U pip # parfois nécessaire la première fois + pip install -r requirements-devel.txt + +Pour terminer, copier le fichier `cof/settings/secret_example.py` vers +`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique +pour profiter de façon transparente des mises à jour du fichier: + + ln -s secret_example.py cof/settings/secret.py + + +#### Fin d'installation + +Il ne vous reste plus qu'à initialiser les modèles de Django et peupler la base +de donnée avec les données nécessaires au bon fonctionnement de GestioCOF + des +données bidons bien pratiques pour développer avec la commande suivante : + + bash provisioning/prepare_django.sh + +Vous êtes prêts à développer ! Lancer GestioCOF en faisant + + python manage.py runserver + + ### Vagrant -La façon recommandée d'installer GestioCOF sur votre machine est d'utiliser +Une autre façon d'installer GestioCOF sur votre machine est d'utiliser [Vagrant](https://www.vagrantup.com/). Vagrant permet de créer une machine virtuelle minimale sur laquelle tournera GestioCOF; ainsi on s'assure que tout le monde à la même configuration de développement (même sous Windows !), et l'installation se fait en une commande. Pour utiliser Vagrant, il faut le -[télécharger](https://www.vagrantup.com/downloads.html) et l'installer. +[télécharger](https://www.vagrantup.com/downloads.html) et l'installer. Si vous êtes sous Linux, votre distribution propose probablement des paquets Vagrant dans le gestionnaire de paquets (la version sera moins récente, ce qui @@ -83,55 +136,6 @@ Ce serveur se lance tout seul et est accessible en dehors de la VM à l'url code change, il faut relancer le worker avec `sudo systemctl restart worker.service` pour visualiser la dernière version du code. - -### Installation manuelle - -Vous pouvez opter pour une installation manuelle plutôt que d'utiliser Vagrant, -il est fortement conseillé d'utiliser un environnement virtuel pour Python. - -Il vous faudra installer pip, les librairies de développement de python ainsi -que sqlite3, un moteur de base de données léger et simple d'utilisation. Sous -Debian et dérivées (Ubuntu, ...) : - - sudo apt-get install python3-pip python3-dev sqlite3 - -Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; -fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF -(le dossier où se trouve ce README), et créez-le maintenant : - - python3 -m venv venv - -Pour l'activer, il faut faire - - . venv/bin/activate - -dans le même dossier. - -Vous pouvez maintenant installer les dépendances Python depuis le fichier -`requirements-devel.txt` : - - pip install -U pip - pip install -r requirements-devel.txt - -Pour terminer, copier le fichier `cof/settings/secret_example.py` vers -`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique -pour profiter de façon transparente des mises à jour du fichier: - - ln -s secret_example.py cof/settings/secret.py - - -#### Fin d'installation - -Il ne vous reste plus qu'à initialiser les modèles de Django et peupler la base -de donnée avec les données nécessaires au bon fonctionnement de GestioCOF + des -données bidons bien pratiques pour développer avec la commande suivante : - - bash provisioning/prepare_django.sh - -Vous êtes prêts à développer ! Lancer GestioCOF en faisant - - python manage.py runserver - ### Mise à jour Pour mettre à jour les paquets Python, utiliser la commande suivante : From 769f4fc7b811994aa20fed6a165372127d4e6558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 14 Apr 2018 14:15:29 +0200 Subject: [PATCH 32/49] README: mention the test database and unit tests --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 939d8ac7..a97e623e 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,32 @@ Pour mettre à jour les modèles après une migration, il faut ensuite faire : python manage.py migrate +## Outils pour développer + +### Base de donnée + +Quelle que soit la méthode d'installation choisie, la base de donnée locale est + peuplée avec des données artificielles pour faciliter le développement. + +- Un compte `root` (mot de passe `root`) avec tous les accès est créé. Connectez + vous sur ce compte pour accéder à tout GestioCOF. +- Des comptes utilisateurs COF et non-COF sont créés ainsi que quelques + spectacles BdA et deux tirages au sort pour jouer avec les fonctionnalités du BdA. +- À chaque compte est associé un trigramme K-Fêt +- Un certain nombre d'articles K-Fêt sont renseignés. + +### Tests unitaires + +On écrit désormais des tests unitaires qui sont lancés automatiquement sur gitlab +à chaque push. Il est conseillé de lancer les tests sur sa machine avant de proposer un patch pour s'assurer qu'on ne casse pas une fonctionnalité existante. + +Pour lancer les tests : + +``` +python manage.py test +``` + + ## Documentation utilisateur Une brève documentation utilisateur est accessible sur le From 2faa8d6b65ff2d919fa26ebc3c83036c9db339cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 14 Apr 2018 23:11:14 +0200 Subject: [PATCH 33/49] =?UTF-8?q?README:=20typo,=20some=20links,=20?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a97e623e..a0dc5bc1 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ ## Installation -Il est possible d'installer vargant sur votre machine de deux façons différentes : +Il est possible d'installer GestioCOF sur votre machine de deux façons différentes : -- L'installation manuelle (**recommandée** sous linux et OSX), plus légère -- L'installation via vagrant qui fonctionne aussi sous windows mais un peu plus lourde +- L'[installation manuelle](#installation-manuelle) (**recommandée** sous linux et OSX), plus légère +- L'[installation via vagrant](#vagrant) qui fonctionne aussi sous windows mais un peu plus lourde ### Installation manuelle @@ -23,7 +23,7 @@ Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF (le dossier où se trouve ce README), et créez-le maintenant : - virtualenv -p python3 venv + python3 -m venv venv Pour l'activer, il faut taper @@ -52,6 +52,9 @@ données bidons bien pratiques pour développer avec la commande suivante : bash provisioning/prepare_django.sh +Voir le paragraphe ["outils pour développer"](#outils-pour-d-velopper) plus bas +pour plus de détails. + Vous êtes prêts à développer ! Lancer GestioCOF en faisant python manage.py runserver From e21666a1129a46a0fd621cc753bfe3522d1075b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 16 Apr 2018 16:34:34 +0200 Subject: [PATCH 34/49] Fix old-style urls (registration) --- cof/urls.py | 3 ++- gestioncof/templates/gestioncof/registration_form.html | 2 +- gestioncof/templates/registration.html | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cof/urls.py b/cof/urls.py index 8aaa2bee..5e4e806c 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -68,7 +68,8 @@ urlpatterns = [ url(r'^registration/empty$', gestioncof_views.registration_form2, name="empty-registration"), # Autocompletion - url(r'^autocomplete/registration$', autocomplete), + url(r'^autocomplete/registration$', autocomplete, + name="cof.registration.autocomplete"), url(r'^user/autocomplete$', gestioncof_views.user_autocomplete, name='cof-user-autocomplete'), # Interface admin diff --git a/gestioncof/templates/gestioncof/registration_form.html b/gestioncof/templates/gestioncof/registration_form.html index 8668152b..37f24cff 100644 --- a/gestioncof/templates/gestioncof/registration_form.html +++ b/gestioncof/templates/gestioncof/registration_form.html @@ -7,7 +7,7 @@ {% else %}

    Inscription d'un nouveau compte (extérieur ?)

    {% endif %} - + {% csrf_token %}
    {{ user_form | bootstrap }} diff --git a/gestioncof/templates/registration.html b/gestioncof/templates/registration.html index 99ab3e73..6e6421cc 100644 --- a/gestioncof/templates/registration.html +++ b/gestioncof/templates/registration.html @@ -18,7 +18,7 @@ // On attend que la page soit prête pour executer le code $(document).ready(function() { $('input#search_autocomplete').yourlabsAutocomplete({ - url: '{% url 'gestioncof.autocomplete.autocomplete' %}', + url: '{% url 'cof.registration.autocomplete' %}', minimumCharacters: 3, id: 'search_autocomplete', choiceSelector: 'li:has(a)', From ece9a54df395f27efcf9ad988cfe9311f04af4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 14 May 2018 13:22:59 +0200 Subject: [PATCH 35/49] Upgrade to reCAPTCHA v2 reCAPTCHA v1 has been shut down since March 2018. We now uses reCAPTCHA v2: - user must check a simple checkbox (No CAPTCHA), - eventually he must validate a challenge. Moving keys settings allows to use the captcha for development. Fixes #192. --- cof/settings/common.py | 11 ++++++++--- cof/settings/prod.py | 6 +++++- gestioncof/templates/demande-petit-cours-raw.html | 2 +- requirements.txt | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cof/settings/common.py b/cof/settings/common.py index f53a46b8..02c796ad 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -42,9 +42,6 @@ REDIS_DB = import_secret("REDIS_DB") REDIS_HOST = import_secret("REDIS_HOST") REDIS_PORT = import_secret("REDIS_PORT") -RECAPTCHA_PUBLIC_KEY = import_secret("RECAPTCHA_PUBLIC_KEY") -RECAPTCHA_PRIVATE_KEY = import_secret("RECAPTCHA_PRIVATE_KEY") - KFETOPEN_TOKEN = import_secret("KFETOPEN_TOKEN") LDAP_SERVER_URL = import_secret("LDAP_SERVER_URL") @@ -207,6 +204,14 @@ AUTHENTICATION_BACKENDS = ( 'kfet.auth.backends.GenericBackend', ) + +# reCAPTCHA settings +# https://github.com/praekelt/django-recaptcha +# +# Default settings authorize reCAPTCHA usage for local developement. +# Public and private keys are appended in the 'prod' module settings. + +NOCAPTCHA = True RECAPTCHA_USE_SSL = True CORS_ORIGIN_WHITELIST = ( diff --git a/cof/settings/prod.py b/cof/settings/prod.py index 2ffdf02f..fcdb3fdb 100644 --- a/cof/settings/prod.py +++ b/cof/settings/prod.py @@ -6,7 +6,7 @@ The settings that are not listed here are imported from .common import os from .common import * # NOQA -from .common import BASE_DIR +from .common import BASE_DIR, import_secret DEBUG = False @@ -28,3 +28,7 @@ STATIC_ROOT = os.path.join( STATIC_URL = "/gestion/static/" MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media") MEDIA_URL = "/gestion/media/" + + +RECAPTCHA_PUBLIC_KEY = import_secret("RECAPTCHA_PUBLIC_KEY") +RECAPTCHA_PRIVATE_KEY = import_secret("RECAPTCHA_PRIVATE_KEY") diff --git a/gestioncof/templates/demande-petit-cours-raw.html b/gestioncof/templates/demande-petit-cours-raw.html index f9bafd8e..a218a0e0 100644 --- a/gestioncof/templates/demande-petit-cours-raw.html +++ b/gestioncof/templates/demande-petit-cours-raw.html @@ -7,7 +7,7 @@ {% if success %}

    Votre demande a été enregistrée avec succès !

    {% else %} - + {% csrf_token %}
    {{ form | bootstrap }} diff --git a/requirements.txt b/requirements.txt index 8ddf0c64..19b185c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ django-autocomplete-light==3.1.3 django-autoslug==1.9.3 django-cas-ng==3.5.7 django-djconfig==0.5.3 -django-recaptcha==1.2.1 +django-recaptcha==1.4.0 django-redis-cache==1.7.1 icalendar psycopg2 From 2a9125ffaaad0dc5ae48856426f8011d3b35a9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 24 May 2018 21:23:46 +0200 Subject: [PATCH 36/49] resolve migration conflict --- bda/migrations/0013_merge_20180524_2123.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 bda/migrations/0013_merge_20180524_2123.py diff --git a/bda/migrations/0013_merge_20180524_2123.py b/bda/migrations/0013_merge_20180524_2123.py new file mode 100644 index 00000000..ae8b0630 --- /dev/null +++ b/bda/migrations/0013_merge_20180524_2123.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.13 on 2018-05-24 19:23 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bda', '0012_notif_time'), + ('bda', '0012_swap_double_choice'), + ] + + operations = [ + ] From b0301f0304b4665d0ef21cd691c465260962dbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 28 May 2018 00:07:34 +0200 Subject: [PATCH 37/49] fix slugurl name error --- kfet/templates/kfet/base_nav.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/templates/kfet/base_nav.html b/kfet/templates/kfet/base_nav.html index f4c07e05..1cded20b 100644 --- a/kfet/templates/kfet/base_nav.html +++ b/kfet/templates/kfet/base_nav.html @@ -1,7 +1,7 @@ {% load i18n static %} {% load wagtailcore_tags %} -{% slugurl "kfet" as kfet_home_url %} +{% slugurl "k-fet" as kfet_home_url %}
    {{ form.as_table }} From 837b48af368115c813c0d2c6d720b81a8b917b1e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 29 May 2018 14:39:29 +0200 Subject: [PATCH 39/49] Fix js path for autocomplete --- kfet/templates/kfet/account_create_special.html | 2 +- kfet/templates/kfet/kpsul.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kfet/templates/kfet/account_create_special.html b/kfet/templates/kfet/account_create_special.html index ecd6ac22..cd5ce7ba 100644 --- a/kfet/templates/kfet/account_create_special.html +++ b/kfet/templates/kfet/account_create_special.html @@ -5,7 +5,7 @@ {% block header-title %}Création d'un compte{% endblock %} {% block extra_head %} - + {% endblock %} {% block main-class %}content-form{% endblock %} diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index a6a01d84..08b060bf 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -3,7 +3,7 @@ {% block extra_head %} - + {% endblock %} From 12ae10f2c4e2d98daa23bc4412ab9f6d775623df Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 30 May 2018 10:13:37 +0200 Subject: [PATCH 40/49] Fix le transfert des reventes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il y avait une typo qui causait une erreur quand on voulait transférer une revente. --- bda/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bda/views.py b/bda/views.py index 9593404e..b49eb030 100644 --- a/bda/views.py +++ b/bda/views.py @@ -410,7 +410,7 @@ def revente_manage(request, tirage_id): soldform = SoldForm(participant, request.POST, prefix='sold') if soldform.is_valid(): reventes = soldform.cleaned_data['reventes'] - for reventes in reventes: + for revente in reventes: revente.attribution.participant = revente.soldTo revente.attribution.save() From 68e71317cbf42f52dad5789d5e349e8f08309be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 1 Jun 2018 17:08:24 +0200 Subject: [PATCH 41/49] Hotfix: broken urls for mailing lists --- cof/urls.py | 6 ++++-- gestioncof/templates/utile_bda.html | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cof/urls.py b/cof/urls.py index 5e4e806c..a1d0c9bf 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -84,10 +84,12 @@ urlpatterns = [ name='utile_cof'), url(r'^utile_bda$', gestioncof_views.utile_bda, name='utile_bda'), - url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff), + url(r'^utile_bda/bda_diff$', gestioncof_views.liste_bdadiff, + name="ml_diffbda"), url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof, name='ml_diffcof'), - url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente), + url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente, + name="ml_bda_revente"), url(r'^k-fet/', include('kfet.urls')), url(r'^cms/', include(wagtailadmin_urls)), url(r'^documents/', include(wagtaildocs_urls)), diff --git a/gestioncof/templates/utile_bda.html b/gestioncof/templates/utile_bda.html index 8948de97..11e96f72 100644 --- a/gestioncof/templates/utile_bda.html +++ b/gestioncof/templates/utile_bda.html @@ -7,7 +7,7 @@

    Liens utiles du BdA

    Listes mail

    {% endblock %} From 645c01ebd19f883e35e24cf149d41d685669f50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 16 Jun 2018 12:33:51 +0200 Subject: [PATCH 42/49] =?UTF-8?q?kfet=20--=20As=20a=20kfet=20staff,=20remo?= =?UTF-8?q?ve=20the=20requirement=20to=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit provide a password in the edit view of an account. --- kfet/forms.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/kfet/forms.py b/kfet/forms.py index 03fcce3a..522f20de 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -75,14 +75,19 @@ class AccountRestrictForm(AccountForm): class Meta(AccountForm.Meta): fields = ['is_frozen'] + class AccountPwdForm(forms.Form): pwd1 = forms.CharField( - label="Mot de passe K-Fêt", - help_text="Le mot de passe doit contenir au moins huit caractères", - widget=forms.PasswordInput) + label="Mot de passe K-Fêt", + required=False, + help_text="Le mot de passe doit contenir au moins huit caractères", + widget=forms.PasswordInput, + ) pwd2 = forms.CharField( - label="Confirmer le mot de passe", - widget=forms.PasswordInput) + label="Confirmer le mot de passe", + required=False, + widget=forms.PasswordInput, + ) def clean(self): pwd1 = self.cleaned_data.get('pwd1', '') @@ -93,6 +98,7 @@ class AccountPwdForm(forms.Form): raise ValidationError("Les mots de passes sont différents") super().clean() + class CofForm(forms.ModelForm): def clean_is_cof(self): instance = getattr(self, 'instance', None) From 898a354c2d419de3a9887a8eb2ed9b438f296b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Aug 2018 18:11:10 +0200 Subject: [PATCH 43/49] Members can change their registration email --- gestioncof/forms.py | 22 ++++------- gestioncof/templates/gestioncof/profile.html | 41 +++++++++----------- gestioncof/tests/test_views.py | 6 +-- gestioncof/views.py | 24 +++++++----- 4 files changed, 44 insertions(+), 49 deletions(-) diff --git a/gestioncof/forms.py b/gestioncof/forms.py index 4a9087fd..1fcc6ea6 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -170,25 +170,16 @@ class EventStatusFilterForm(forms.Form): yield ("has_paid", None, value) -class UserProfileForm(forms.ModelForm): - first_name = forms.CharField(label=_('Prénom'), max_length=30) - last_name = forms.CharField(label=_('Nom'), max_length=30) +class UserForm(forms.ModelForm): + class Meta: + model = User + fields = ["first_name", "last_name", "email"] - def __init__(self, *args, **kw): - super().__init__(*args, **kw) - self.fields['first_name'].initial = self.instance.user.first_name - self.fields['last_name'].initial = self.instance.user.last_name - - def save(self, *args, **kw): - super().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 ProfileForm(forms.ModelForm): class Meta: model = CofProfile - fields = ["first_name", "last_name", "phone", "mailing_cof", - "mailing_bda", "mailing_bda_revente"] + fields = ["phone", "mailing_cof", "mailing_bda", "mailing_bda_revente"] class RegistrationUserForm(forms.ModelForm): @@ -252,6 +243,7 @@ class RegistrationProfileForm(forms.ModelForm): "departement", "is_cof", "type_cotiz", "mailing_cof", "mailing_bda", "mailing_bda_revente", "comments") + STATUS_CHOICES = (('no', 'Non'), ('wait', 'Oui mais attente paiement'), ('paid', 'Oui payé'),) diff --git a/gestioncof/templates/gestioncof/profile.html b/gestioncof/templates/gestioncof/profile.html index 5decdfb3..9d418ef6 100644 --- a/gestioncof/templates/gestioncof/profile.html +++ b/gestioncof/templates/gestioncof/profile.html @@ -4,26 +4,23 @@ {% block page_size %}col-sm-8{%endblock%} {% block realcontent %} -

    Modifier mon profil

    - -
    - {% csrf_token %} - - {% for field in form %} - {{ field | bootstrap }} - {% endfor %} - -
    - {% if user.profile.comments %} -
    -

    Commentaires

    -

    - {{ user.profile.comments }} -

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

    Modifier mon profil

    +
    +
    + {% csrf_token %} + {{ user_form | bootstrap }} + {{ profile_form | bootstrap }} +
    + + {% if user.profile.comments %} +
    +

    Commentaires

    +

    {{ user.profile.comments }}

    +
    + {% endif %} + +
    + +
    + {% endblock %} diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py index 47139327..1067e586 100644 --- a/gestioncof/tests/test_views.py +++ b/gestioncof/tests/test_views.py @@ -46,9 +46,9 @@ class ProfileViewTests(ViewTestCaseMixin, TestCase): u = self.users['member'] r = self.client.post(self.url, { - 'first_name': 'First', - 'last_name': 'Last', - 'phone': '', + 'u-first_name': 'First', + 'u-last_name': 'Last', + 'p-phone': '', # 'mailing_cof': '1', # 'mailing_bda': '1', # 'mailing_bda_revente': '1', diff --git a/gestioncof/views.py b/gestioncof/views.py index 6126eb10..64fe89a0 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -32,7 +32,8 @@ from gestioncof.models import EventCommentField, EventCommentValue, \ from gestioncof.models import CofProfile, Club from gestioncof.decorators import buro_required, cof_required from gestioncof.forms import ( - UserProfileForm, EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm, + UserForm, ProfileForm, + EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, RegistrationProfileForm, EventForm, CalendarForm, EventFormset, RegistrationPassUserForm, ClubsForm, GestioncofConfigForm ) @@ -334,15 +335,20 @@ def survey_status(request, survey_id): @cof_required def profile(request): + user = request.user + data = request.POST if request.method == "POST" else None + user_form = UserForm(data=data, instance=user, prefix="u") + profile_form = ProfileForm(data=data, instance=user.profile, prefix="p") if request.method == "POST": - form = UserProfileForm(request.POST, instance=request.user.profile) - if form.is_valid(): - form.save() - messages.success(request, - "Votre profil a été mis à jour avec succès !") - else: - form = UserProfileForm(instance=request.user.profile) - return render(request, "gestioncof/profile.html", {"form": form}) + if user_form.is_valid() and profile_form.is_valid(): + user_form.save() + profile_form.save() + messages.success( + request, + _("Votre profil a été mis à jour avec succès !") + ) + context = {"user_form": user_form, "profile_form": profile_form} + return render(request, "gestioncof/profile.html", context) def registration_set_ro_fields(user_form, profile_form): From 66184fbee649a3eefc7ab6673f05b5814ee74721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Aug 2018 18:34:05 +0200 Subject: [PATCH 44/49] CI: set python version to 3.5 --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19bcc736..e0ced08d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,5 @@ +image: "python:3.5" + services: - postgres:latest - redis:latest @@ -34,6 +36,7 @@ before_script: # Remove the old test database if it has not been done yet - psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB" - pip install --upgrade --cache-dir vendor/pip -t vendor/python -r requirements.txt + - python --version test: stage: test From 91393dcea7caf4da586a66390c55ae88daed3272 Mon Sep 17 00:00:00 2001 From: Theo Delemazure Date: Sun, 2 Sep 2018 20:34:09 +0200 Subject: [PATCH 45/49] Update models.py --- gestioncof/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gestioncof/models.py b/gestioncof/models.py index 0d816155..8a5b6a53 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -72,6 +72,7 @@ class CofProfile(models.Model): TYPE_COTIZ_CHOICES)) mailing_cof = models.BooleanField("Recevoir les mails COF", default=False) mailing_bda = models.BooleanField("Recevoir les mails BdA", default=False) + mailing_unernestaparis = models.BooleanField("Recevoir les mails unErnestAParis", default=False) mailing_bda_revente = models.BooleanField( "Recevoir les mails de revente de places BdA", default=False) comments = models.TextField( From 73cf39baa81ae39c4f70192e2a6ac160c4e31fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 2 Sep 2018 23:25:58 +0200 Subject: [PATCH 46/49] missing migration --- .../0014_cofprofile_mailing_unernestaparis.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py diff --git a/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py b/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py new file mode 100644 index 00000000..1d842329 --- /dev/null +++ b/gestioncof/migrations/0014_cofprofile_mailing_unernestaparis.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.15 on 2018-09-02 21:13 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gestioncof', '0013_pei'), + ] + + operations = [ + migrations.AddField( + model_name='cofprofile', + name='mailing_unernestaparis', + field=models.BooleanField(default=False, verbose_name='Recevoir les mails unErnestAParis'), + ), + ] From 327ef210dbc0e74f2b6c1968cebcee2c08c1beb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 2 Sep 2018 23:26:18 +0200 Subject: [PATCH 47/49] make unernestaparis visible in forms --- gestioncof/forms.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/gestioncof/forms.py b/gestioncof/forms.py index 1fcc6ea6..4ad9b058 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -179,7 +179,13 @@ class UserForm(forms.ModelForm): class ProfileForm(forms.ModelForm): class Meta: model = CofProfile - fields = ["phone", "mailing_cof", "mailing_bda", "mailing_bda_revente"] + fields = [ + "phone", + "mailing_cof", + "mailing_bda", + "mailing_bda_revente", + "mailing_unernestaparis" + ] class RegistrationUserForm(forms.ModelForm): @@ -223,6 +229,7 @@ class RegistrationProfileForm(forms.ModelForm): self.fields['mailing_cof'].initial = True self.fields['mailing_bda'].initial = True self.fields['mailing_bda_revente'].initial = True + self.fields['mailing_unernestaparis'].initial = True self.fields.keyOrder = [ 'login_clipper', @@ -234,14 +241,16 @@ class RegistrationProfileForm(forms.ModelForm): 'mailing_cof', 'mailing_bda', 'mailing_bda_revente', + "mailing_unernestaparis", 'comments' - ] + ] class Meta: model = CofProfile fields = ("login_clipper", "phone", "occupation", "departement", "is_cof", "type_cotiz", "mailing_cof", - "mailing_bda", "mailing_bda_revente", "comments") + "mailing_bda", "mailing_bda_revente", + "mailing_unernestaparis", "comments") STATUS_CHOICES = (('no', 'Non'), From a750c62baf48cfab57d01f2d9b09372150fd06da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 2 Sep 2018 23:27:21 +0200 Subject: [PATCH 48/49] New year, new promotion: 2018 --- kfet/migrations/0064_promo_2018.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 kfet/migrations/0064_promo_2018.py diff --git a/kfet/migrations/0064_promo_2018.py b/kfet/migrations/0064_promo_2018.py new file mode 100644 index 00000000..c99d85b5 --- /dev/null +++ b/kfet/migrations/0064_promo_2018.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.15 on 2018-09-02 21:13 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('kfet', '0063_promo'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='promo', + field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018)], default=2018, null=True), + ), + ] From f297a1a0cf4b858a0d61b32be3b581fe9826df13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 9 Sep 2018 07:20:18 +0200 Subject: [PATCH 49/49] =?UTF-8?q?update=20hardcoded=20Mega=20views=20for?= =?UTF-8?q?=202018=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gestioncof/tests/test_views.py | 6 ++--- gestioncof/views.py | 43 ++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py index 1067e586..f6dd7eb9 100644 --- a/gestioncof/tests/test_views.py +++ b/gestioncof/tests/test_views.py @@ -191,14 +191,14 @@ class MegaHelpers: u2 = create_user('u2') u2.profile.save() - m = Event.objects.create(title='MEGA 2017') + m = Event.objects.create(title='MEGA 2018') - cf1 = m.commentfields.create(name='Commentaire') + cf1 = m.commentfields.create(name='Commentaires') cf2 = m.commentfields.create( name='Comment Field 2', fieldtype='char', ) - option_type = m.options.create(name='Conscrit/Orga ?') + option_type = m.options.create(name='Orga ? Conscrit ?') choice_orga = option_type.choices.create(value='Orga') choice_conscrit = option_type.choices.create(value='Conscrit') diff --git a/gestioncof/views.py b/gestioncof/views.py index 64fe89a0..d77794bb 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -594,6 +594,19 @@ def export_members(request): return response +# ---------------------------------------- +# Début des exports Mega machins hardcodés +# ---------------------------------------- + + +MEGA_YEAR = 2018 +MEGA_EVENT_NAME = "MEGA 2018" +MEGA_COMMENTFIELD_NAME = "Commentaires" +MEGA_CONSCRITORGAFIELD_NAME = "Orga ? Conscrit ?" +MEGA_CONSCRIT = "Conscrit" +MEGA_ORGA = "Orga" + + def csv_export_mega(filename, qs): response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=' + filename @@ -615,13 +628,13 @@ def csv_export_mega(filename, qs): @buro_required def export_mega_remarksonly(request): - filename = 'remarques_mega_2017.csv' + filename = 'remarques_mega_{}.csv'.format(MEGA_YEAR) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=' + filename writer = unicodecsv.writer(response) - event = Event.objects.get(title="MEGA 2017") - commentfield = event.commentfields.get(name="Commentaire") + event = Event.objects.get(title=MEGA_EVENT_NAME) + commentfield = event.commentfields.get(name=MEGA_COMMENTFIELD_NAME) for val in commentfield.values.all(): reg = val.registration user = reg.user @@ -653,32 +666,36 @@ def export_mega_remarksonly(request): @buro_required def export_mega_orgas(request): - event = Event.objects.get(title="MEGA 2017") - type_option = event.options.get(name="Conscrit/Orga ?") - participant_type = type_option.choices.get(value="Orga").id + event = Event.objects.get(title=MEGA_EVENT_NAME) + type_option = event.options.get(name=MEGA_CONSCRITORGAFIELD_NAME) + participant_type = type_option.choices.get(value=MEGA_ORGA).id qs = EventRegistration.objects.filter(event=event).filter( options__id=participant_type ) - return csv_export_mega('orgas_mega_2017.csv', qs) + return csv_export_mega('orgas_mega_{}.csv'.format(MEGA_YEAR), qs) @buro_required def export_mega_participants(request): - event = Event.objects.get(title="MEGA 2017") - type_option = event.options.get(name="Conscrit/Orga ?") - participant_type = type_option.choices.get(value="Conscrit").id + event = Event.objects.get(title=MEGA_EVENT_NAME) + type_option = event.options.get(name=MEGA_CONSCRITORGAFIELD_NAME) + participant_type = type_option.choices.get(value=MEGA_CONSCRIT).id qs = EventRegistration.objects.filter(event=event).filter( options__id=participant_type ) - return csv_export_mega('participants_mega_2017.csv', qs) + return csv_export_mega('conscrits_mega_{}.csv'.format(MEGA_YEAR), qs) @buro_required def export_mega(request): - event = Event.objects.filter(title="MEGA 2017") + event = Event.objects.filter(title=MEGA_EVENT_NAME) qs = EventRegistration.objects.filter(event=event) \ .order_by("user__username") - return csv_export_mega('all_mega_2017.csv', qs) + return csv_export_mega('all_mega_{}.csv'.format(MEGA_YEAR), qs) + +# ------------------------------ +# Fin des exports Mega hardcodés +# ------------------------------ @buro_required