From ac0346d69f329a29f367f290f1a630a37aaff695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 31 May 2016 20:04:27 +0200 Subject: [PATCH 01/37] =?UTF-8?q?Ajout=20d'un=20champ=20'tirage'=20aux=20m?= =?UTF-8?q?od=C3=A8les?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bda/models.py b/bda/models.py index 11c9dd3b..cd013d0e 100644 --- a/bda/models.py +++ b/bda/models.py @@ -23,6 +23,7 @@ class Spectacle (models.Model): price = models.FloatField("Prix d'une place", blank = True) slots = models.IntegerField ("Places") priority = models.IntegerField ("Priorité", default = 1000) + tirage = models.IntegerField ("Tirage") class Meta: verbose_name = "Spectacle" @@ -68,6 +69,7 @@ class ChoixSpectacle (models.Model): spectacle = models.ForeignKey(Spectacle, related_name = "participants") priority = models.PositiveIntegerField("Priorité") double_choice = models.CharField("Nombre de places", default = "1", choices = DOUBLE_CHOICES, max_length = 10) + tirage = models.IntegerField("Tirage") def get_double(self): return self.double_choice != "1" @@ -87,6 +89,7 @@ class Attribution (models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name = "attribues") given = models.BooleanField(u"Donnée", default = False) + tirage = models.IntegerField("Tirage") def __unicode__ (self): return u"%s -- %s" % (self.participant, self.spectacle) From 7c7488f1685065221461cb9a996820ab5bbcc165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 1 Jun 2016 16:07:19 +0200 Subject: [PATCH 02/37] Suppression des vieux dossiers --- bda2/__init__.py | 0 bda2/admin.py | 177 ---------- bda2/algorithm.py | 104 ------ bda2/autocomplete_light_registry.py | 9 - bda2/difftobda | 421 ------------------------ bda2/migrations/0001_initial.py | 109 ------ bda2/migrations/__init__.py | 0 bda2/models.py | 78 ----- bda2/static/css/bda.css | 10 - bda2/templates/bda-attrib-extra.html | 27 -- bda2/templates/bda-attrib.html | 41 --- bda2/templates/bda-emails.html | 7 - bda2/templates/bda-notpaid.html | 6 - bda2/templates/bda-revente.html | 26 -- bda2/templates/bda-success.html | 12 - bda2/templates/bda-token.html | 13 - bda2/templates/bda-unpaid.html | 7 - bda2/templates/etat-places.html | 11 - bda2/templates/inscription-bda.html | 116 ------- bda2/templates/inscription-formset.html | 40 --- bda2/templates/spectacle_list.html | 11 - bda2/tests.py | 16 - bda2/views.py | 248 -------------- bda3/__init__.py | 0 bda3/admin.py | 180 ---------- bda3/algorithm.py | 104 ------ bda3/autocomplete_light_registry.py | 9 - bda3/difftobda | 421 ------------------------ bda3/migrations/0001_initial.py | 109 ------ bda3/migrations/__init__.py | 0 bda3/models.py | 78 ----- bda3/static/css/bda.css | 10 - bda3/templates/spectacle_list.html | 11 - bda3/tests.py | 16 - bda3/views.py | 249 -------------- 35 files changed, 2676 deletions(-) delete mode 100644 bda2/__init__.py delete mode 100644 bda2/admin.py delete mode 100644 bda2/algorithm.py delete mode 100644 bda2/autocomplete_light_registry.py delete mode 100644 bda2/difftobda delete mode 100644 bda2/migrations/0001_initial.py delete mode 100644 bda2/migrations/__init__.py delete mode 100644 bda2/models.py delete mode 100644 bda2/static/css/bda.css delete mode 100644 bda2/templates/bda-attrib-extra.html delete mode 100644 bda2/templates/bda-attrib.html delete mode 100644 bda2/templates/bda-emails.html delete mode 100644 bda2/templates/bda-notpaid.html delete mode 100644 bda2/templates/bda-revente.html delete mode 100644 bda2/templates/bda-success.html delete mode 100644 bda2/templates/bda-token.html delete mode 100644 bda2/templates/bda-unpaid.html delete mode 100644 bda2/templates/etat-places.html delete mode 100644 bda2/templates/inscription-bda.html delete mode 100644 bda2/templates/inscription-formset.html delete mode 100644 bda2/templates/spectacle_list.html delete mode 100644 bda2/tests.py delete mode 100644 bda2/views.py delete mode 100644 bda3/__init__.py delete mode 100644 bda3/admin.py delete mode 100644 bda3/algorithm.py delete mode 100644 bda3/autocomplete_light_registry.py delete mode 100644 bda3/difftobda delete mode 100644 bda3/migrations/0001_initial.py delete mode 100644 bda3/migrations/__init__.py delete mode 100644 bda3/models.py delete mode 100644 bda3/static/css/bda.css delete mode 100644 bda3/templates/spectacle_list.html delete mode 100644 bda3/tests.py delete mode 100644 bda3/views.py diff --git a/bda2/__init__.py b/bda2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/bda2/admin.py b/bda2/admin.py deleted file mode 100644 index 84eebfa3..00000000 --- a/bda2/admin.py +++ /dev/null @@ -1,177 +0,0 @@ -# coding: utf-8 - -from django.core.mail import send_mail -from django.contrib.contenttypes.models import ContentType - -from django.contrib import admin -from django.db.models import Sum, Count -from bda2.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution - -class ChoixSpectacleInline(admin.TabularInline): - model = ChoixSpectacle - sortable_field_name = "priority" - -class AttributionInline(admin.TabularInline): - model = Attribution - -class ParticipantAdmin(admin.ModelAdmin): - #inlines = [ChoixSpectacleInline] - inlines = [AttributionInline] - def get_queryset(self, request): - return Participant.objects.annotate(nb_places = Count('attributions'), - total = Sum('attributions__price')) - def nb_places(self, obj): - return obj.nb_places - nb_places.admin_order_field = "nb_places" - nb_places.short_description = "Nombre de places" - def total(self, obj): - tot = obj.total - if tot: return u"%.02f €" % tot - else: return u"0 €" - total.admin_order_field = "total" - total.short_description = "Total à payer" - list_display = ("user", "nb_places", "total", "paid", "paymenttype") - list_filter = ("paid",) - search_fields = ('user__username', 'user__first_name', 'user__last_name') - actions = ['send_attribs',] - actions_on_bottom = True - list_per_page = 400 - - def send_choices(self, request, queryset): - for member in queryset.all(): - choices = member.choixspectacle_set.order_by('priority').all() - if len(choices) == 0: - continue - mail = u"""Cher(e) %s, -Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""" % member.user.get_full_name() - next_rank = 1 - member_shows = {} - for choice in choices: - if choice.spectacle in member_shows: continue - else: member_shows[choice.spectacle] = True - extra = "" - if choice.double: - extra += u" ; deux places" - if choice.autoquit: - extra += u" ; désistement automatique" - mail += u"- Choix %d : %s%s\n" % (next_rank, choice.spectacle, extra) - next_rank += 1 - mail += u"""\nSi cette liste est incorrecte, merci de nous contacter au plus vite (avant samedi 6 octobre 18h). - -Artistiquement, -Le BdA""" - send_mail ("Choix de spectacles (BdA du COF)", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: - message_bit = u"1 membre a" - plural = "" - else: - message_bit = u"%d membres ont" % count - plural = "s" - self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural)) - send_choices.short_description = u"Envoyer les choix par mail" - - def send_attribs(self, request, queryset): - for member in queryset.all(): - attribs = member.attributions.all() - if len(attribs) == 0: - mail = u"""Cher-e %s, - -Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as -obtenu aucune place. - -Nous sommes conscients que le nombre de places proposées lors de ce tirage -au sort est très restreint, mais nous sommes limités par les quotas que -nous imposent les théâtres. - -Nous proposons cependant de nombreuses offres hors-tirage tout au long de -l'année, et nous t'invitons à nous contacter si l'une d'entre elles t'intéresse ! --- -Le (nouveau) Bureau des Arts -(Thomas, Caroline, Antonin, Cécile, Hugo) - -""" - name = member.user.get_full_name() - mail = mail % name - else: - mail = u"""Cher-e %s, - -Tu t'es inscrit-e pour le tirage au sort du BdA. Tu as été sélectionné-e -pour les spectacles suivants : - -%s - -Nous sommes conscients que le nombre de places proposées lors de ce tirage -au sort est très restreint, mais nous sommes limités par les quotas que -nous imposent les théâtres. - -*Paiement* -L'intégralité de ces places de spectacles est à régler à partir du lundi -18 janvier et AVANT le vendredi 22 janvier, au bureau du COF pendant les -heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h -et 20h). Des facilités de paiement sont bien évidemment possibles : nous -pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre -paiement en deux fois. Il est possible de payer par carte, chèque ou en espèces. - -*Mode de retrait des places* -Lors du paiement, nous vous donnerons les places physiques que nous possédons, et vous indiquerons -quelles places sont sur listing, à retirer le soir même de la représentation. Nous vous enverrons un mail de rappel quelques jours avant les spectacles. - -Nous vous rappelons que l'obtention de places du BdA vous engage à -respecter les règles de fonctionnement : -http://www.cof.ens.fr/bda/?page_id=1370 -Le système de revente des places via les mails BdA-revente est accessible -directement sur votre compte GestioCOF. - -En vous souhaitant de belles représentations, --- -Le (nouveau) Bureau des Arts -(Thomas, Caroline, Antonin, Cécile, Hugo) -""" - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib - mail = mail % (name, attribs_text) - - send_mail ("[BdA] Résultats du tirage au sort", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: - message_bit = u"1 membre a" - plural = "" - else: - message_bit = u"%d membres ont" % count - plural = "s" - self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural)) - send_attribs.short_description = u"Envoyer les résultats par mail" - -class AttributionAdmin(admin.ModelAdmin): - def paid(self, obj): - return obj.participant.paid - paid.short_description = 'A payé' - paid.boolean = True - list_display = ("id", "spectacle", "participant", "given", "paid") - search_fields = ('spectacle__title', 'participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - -import autocomplete_light -class ChoixSpectacleAdmin(admin.ModelAdmin): - form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) - list_display = ("participant", "spectacle", "priority", "double", "autoquit") - list_filter = ("double", "autoquit") - search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - -class SpectacleAdmin(admin.ModelAdmin): - model = Spectacle - list_display = ("title", "date", "location", "slots", "price") - list_filter = ("location",) - search_fields = ("title", "location__name") - -admin.site.register(Spectacle, SpectacleAdmin) -admin.site.register(Salle) -admin.site.register(Participant, ParticipantAdmin) -admin.site.register(Attribution, AttributionAdmin) -admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin) diff --git a/bda2/algorithm.py b/bda2/algorithm.py deleted file mode 100644 index 623f9756..00000000 --- a/bda2/algorithm.py +++ /dev/null @@ -1,104 +0,0 @@ -# coding: utf-8 - -from django.conf import settings -from django.db.models import Max - -import random - -class Algorithm(object): - - shows = None - ranks = None - origranks = None - double = None - - def __init__(self, shows, members, choices): - """Initialisation : - - on aggrège toutes les demandes pour chaque spectacle dans - show.requests - - on crée des tables de demandes pour chaque personne, afin de - pouvoir modifier les rankings""" - self.max_group = 2 * choices.aggregate(Max('priority'))['priority__max'] - self.shows = [] - showdict = {} - for show in shows: - show.nrequests = 0 - showdict[show] = show - show.requests = [] - self.shows.append(show) - self.ranks = {} - self.origranks = {} - self.choices = {} - next_rank = {} - member_shows = {} - for member in members: - self.ranks[member] = {} - self.choices[member] = {} - next_rank[member] = 1 - member_shows[member] = {} - for choice in choices: - member = choice.participant - if choice.spectacle in member_shows[member]: continue - else: member_shows[member][choice.spectacle] = True - showdict[choice.spectacle].requests.append(member) - showdict[choice.spectacle].nrequests += 2 if choice.double else 1 - self.ranks[member][choice.spectacle] = next_rank[member] - next_rank[member] += 2 if choice.double else 1 - self.choices[member][choice.spectacle] = choice - for member in members: - self.origranks[member] = dict(self.ranks[member]) - - def IncrementRanks(self, member, currank, increment = 1): - for show in self.ranks[member]: - if self.ranks[member][show] > currank: - self.ranks[member][show] -= increment - - def appendResult(self, l, member, show): - l.append((member, - self.ranks[member][show], - self.origranks[member][show], - self.choices[member][show].double)) - - """ - Pour les 2 Walkyries: c'est Sandefer - - Pour les 4 places pour l'Oratorio c'est Maxence Arutkin - """ - - def __call__(self, seed): - random.seed(seed) - results = [] - shows = sorted(self.shows, key = lambda x: float(x.nrequests) / x.slots, reverse = True) - for show in shows: - # On regroupe tous les gens ayant le même rang - groups = dict([(i, []) for i in range(1, self.max_group + 1)]) - for member in show.requests: - if self.ranks[member][show] == 0: - raise RuntimeError, (member, show.title) - groups[self.ranks[member][show]].append(member) - # On passe à l'attribution - winners = [] - losers = [] - for i in range(1, self.max_group + 1): - group = list(groups[i]) - random.shuffle(group) - for member in group: - if self.choices[member][show].double: # double - if len(winners) + 1 < show.slots: - self.appendResult(winners, member, show) - self.appendResult(winners, member, show) - elif not self.choices[member][show].autoquit and len(winners) < show.slots: - self.appendResult(winners, member, show) - self.appendResult(losers, member, show) - else: - self.appendResult(losers, member, show) - self.appendResult(losers, member, show) - self.IncrementRanks(member, i, 2) - else: # simple - if len(winners) < show.slots: - self.appendResult(winners, member, show) - else: - self.appendResult(losers, member, show) - self.IncrementRanks(member, i) - results.append((show,winners,losers)) - return results diff --git a/bda2/autocomplete_light_registry.py b/bda2/autocomplete_light_registry.py deleted file mode 100644 index 3254b3c8..00000000 --- a/bda2/autocomplete_light_registry.py +++ /dev/null @@ -1,9 +0,0 @@ -import autocomplete_light - -from bda.models import Participant, Spectacle - -autocomplete_light.register(Participant, search_fields=('user__username','user__first_name','user__last_name'), - autocomplete_js_attributes={'placeholder': 'participant...'}) - -autocomplete_light.register(Spectacle, search_fields=('title',), - autocomplete_js_attributes={'placeholder': 'spectacle...'}) diff --git a/bda2/difftobda b/bda2/difftobda deleted file mode 100644 index 3e6686e5..00000000 --- a/bda2/difftobda +++ /dev/null @@ -1,421 +0,0 @@ -Only in .: .admin.py.swp -Binary files ../bda/__init__.pyc and ./__init__.pyc differ -diff -p -u -r ../bda/admin.py ./admin.py ---- ../bda/admin.py 2013-12-17 10:19:56.000000000 +0100 -+++ ./admin.py 2012-12-08 22:31:46.000000000 +0100 -@@ -4,8 +4,8 @@ from django.core.mail import send_mail - from django.contrib.contenttypes.models import ContentType - - from django.contrib import admin --from django.db.models import Sum, Count --from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution -+from django.db.models import Sum -+from bda2.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution - - class ChoixSpectacleInline(admin.TabularInline): - model = ChoixSpectacle -@@ -17,18 +17,13 @@ class AttributionInline(admin.TabularInl - class ParticipantAdmin(admin.ModelAdmin): - #inlines = [ChoixSpectacleInline] - inlines = [AttributionInline] -- def queryset(self, request): -- return Participant.objects.annotate(nb_places = Count('attributions'), -- total = Sum('attributions__price')) - def nb_places(self, obj): -- return obj.nb_places -- nb_places.admin_order_field = "nb_places" -+ return len(obj.attribution_set.all()) - nb_places.short_description = "Nombre de places" - def total(self, obj): -- tot = obj.total -+ tot = obj.attributions.aggregate(total = Sum('price'))['total'] - if tot: return u"%.02f €" % tot - else: return u"0 €" -- total.admin_order_field = "total" - total.short_description = "Total à payer" - list_display = ("user", "nb_places", "total", "paid", "paymenttype") - list_filter = ("paid",) -@@ -61,7 +56,7 @@ Voici tes choix de spectacles tels que n - Artistiquement, - Le BdA""" - send_mail ("Choix de spectacles (BdA du COF)", mail, -- "bda@ens.fr", [member.user.email], -+ "bda@clipper.ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: -@@ -86,48 +81,41 @@ pour les spectacles suivants : - %s - - *Paiement* --L'intégralité de ces places de spectacles est à régler à partir du jeudi --10 octobre et AVANT le mercredi 23 octobre, au bureau du COF pendant les --heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h --et 20h). Des facilités de paiement sont bien évidemment possibles : nous --pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre --paiement en deux fois. -+Ces spectacles sont à régler avant le lundi 17 décembre, pendant les -+heures de permanences du COF (tous les jours de la semaine entre 12h et -+14h, et entre 18h et 20h). Des facilités de paiement sont bien évidemment -+possibles (encaissement échelonné des chèques). - - *Mode de retrait des places* --Au moment du paiement, une enveloppe vous sera remise, contenant les --places pour l'Opéra de Paris, pour les premiers spectacles de la Comédie --française, certains spectacles du Châtelet et du Théâtre de la Ville. -- --Pour les concerts Radio France, le Théâtre des Champs-Élysées, le théâtre --du Rond-Point, le théâtre de la Colline, le théâtre de l'Athénée, l'IRCAM, --la Cité de la musique et le 104, le Studio-Théâtre de la Comédie --française, les places seront nominatives et à retirer au théâtre le soir --de la représentation au moins une demi-heure avant le début du spectacle. -- --Pour le théâtre de l'Odéon, la salle Richelieu le théâtre du Vieux --colombier de la Comédie française, certains spectacles du théâtre de la --Ville et du théâtre de Châtelet ainsi que pour le théâtre de Chaillot, les --places seront distribuées environ une semaine avant la représentation (un --mail vous en avertira). -- --Nous vous rappelons que l'obtention de places du BdA vous engage à --respecter les règles de fonctionnement : --http://www.cof.ens.fr/bda/?page_id=1370 --Le système de revente des places via les mails BdA-revente sera très --prochainement disponible, directement sur votre compte GestioCOF. -+Pour l'Opéra de Paris, le théâtre de la Colline et le théâtre du Châtelet, -+les places sont à retirer au COF le jour du paiement. -+ -+Pour les concerts Radio France, le théâtre des Champs-Élysées, l'IRCAM -+et le 104, les places seront nominatives et à retirer à la salle le soir de -+la représentation au moins une demi-heure avant le début du spectacle. -+ -+Pour le théâtre de l'Odéon, la Comédie Française, le théâtre de la Ville, -+le théâtre de Chaillot, les places seront distribuées dans vos -+casiers environ une semaine avant la représentation (un mail vous en -+avertira). -+ -+Dans tous les cas, n'hésitez pas à nous contacter si vous avez un doute ! -+ -+Nous profitons aussi de ce message pour vous annoncer qu'un festival de -+courts métrages aura lieu le 21 décembre dans l'école. -+Plus d'informations : http://www.cof.ens.fr/bda/courts. -+ -+Culturellement vôtre, - --En vous souhaitant de très beaux spectacles tout au long de l'année, - -- --Le Bureau des Arts --(Chloé, Emilie, Jaime, Maxime, Olivier) --""" -+Le BdA""" - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib - mail = mail % (name, attribs_text) -- send_mail ("Résultats du tirage au sort", mail, -- "bda@ens.fr", [member.user.email], -+ send_mail ("Places de spectacle (BdA du COF)", mail, -+ "bda@clipper.ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: -@@ -154,13 +142,7 @@ class ChoixSpectacleAdmin(admin.ModelAdm - list_filter = ("double", "autoquit") - search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - --class SpectacleAdmin(admin.ModelAdmin): -- model = Spectacle -- list_display = ("title", "date", "location", "slots", "price") -- list_filter = ("location",) -- search_fields = ("title", "location__name") -- --admin.site.register(Spectacle, SpectacleAdmin) -+admin.site.register(Spectacle) - admin.site.register(Salle) - admin.site.register(Participant, ParticipantAdmin) - admin.site.register(Attribution, AttributionAdmin) -diff -p -u -r ../bda/algorithm.py ./algorithm.py ---- ../bda/algorithm.py 2013-10-07 14:08:44.000000000 +0200 -+++ ./algorithm.py 2012-10-31 23:01:48.000000000 +0100 -@@ -29,24 +29,25 @@ class Algorithm(object): - self.ranks = {} - self.origranks = {} - self.choices = {} -- next_rank = {} -- member_shows = {} - for member in members: -- self.ranks[member] = {} -- self.choices[member] = {} -- next_rank[member] = 1 -- member_shows[member] = {} -- for choice in choices: -- member = choice.participant -- if choice.spectacle in member_shows[member]: continue -- else: member_shows[member][choice.spectacle] = True -- showdict[choice.spectacle].requests.append(member) -- showdict[choice.spectacle].nrequests += 2 if choice.double else 1 -- self.ranks[member][choice.spectacle] = next_rank[member] -- next_rank[member] += 2 if choice.double else 1 -- self.choices[member][choice.spectacle] = choice -- for member in members: -- self.origranks[member] = dict(self.ranks[member]) -+ ranks = {} -+ member_choices = {} -+ member_shows = {} -+ #next_priority = 1 -+ next_rank = 1 -+ for choice in member.choixspectacle_set.order_by('priority').all(): -+ if choice.spectacle in member_shows: continue -+ else: member_shows[choice.spectacle] = True -+ #assert choice.priority == next_priority -+ #next_priority += 1 -+ showdict[choice.spectacle].requests.append(member) -+ showdict[choice.spectacle].nrequests += 2 if choice.double else 1 -+ ranks[choice.spectacle] = next_rank -+ next_rank += 2 if choice.double else 1 -+ member_choices[choice.spectacle] = choice -+ self.ranks[member] = ranks -+ self.choices[member] = member_choices -+ self.origranks[member] = dict(ranks) - - def IncrementRanks(self, member, currank, increment = 1): - for show in self.ranks[member]: -Only in ../bda: algorithm.pyc -Only in .: difftobda -diff -p -u -r ../bda/models.py ./models.py ---- ../bda/models.py 2013-10-10 10:44:43.000000000 +0200 -+++ ./models.py 2012-10-31 23:12:56.000000000 +0100 -@@ -1,7 +1,5 @@ - # coding: utf-8 - --import calendar -- - from django.db import models - from django.contrib.auth.models import User - from django.utils.translation import ugettext_lazy as _ -@@ -19,7 +17,7 @@ class Spectacle (models.Model): - date = models.DateTimeField ("Date & heure") - location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank = True) -- slots_description = models.TextField ("Description des places", blank = True) -+ #slots_description = models.TextField ("Description des places", blank = True) - price = models.FloatField("Prix d'une place", blank = True) - slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default = 1000) -@@ -31,14 +29,11 @@ class Spectacle (models.Model): - def __repr__ (self): - return u"[%s]" % self.__unicode__() - -- def timestamp(self): -- return "%d" % calendar.timegm(self.date.utctimetuple()) -- - def date_no_seconds(self): - return self.date.strftime('%d %b %Y %H:%M') - - def __unicode__ (self): -- return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) -+ return u"%s - %s @ %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) - - PAYMENT_TYPES = ( - ("cash",u"Cash"), -@@ -48,7 +43,7 @@ PAYMENT_TYPES = ( - ) - - class Participant (models.Model): -- user = models.ForeignKey(User, unique = True) -+ user = models.ForeignKey(User, unique = True, related_name = "participants2") - choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by") - attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to") - paid = models.BooleanField (u"A payé", default = False) -Binary files ../bda/models.pyc and ./models.pyc differ -diff -p -u -r ../bda/views.py ./views.py ---- ../bda/views.py 2014-01-04 21:37:15.000000000 +0100 -+++ ./views.py 2013-02-12 22:03:38.000000000 +0100 -@@ -1,23 +1,19 @@ - # coding: utf-8 - --from django.contrib.auth.models import User - from django.shortcuts import render, get_object_or_404 - from django.contrib.auth.decorators import login_required - from django.db import models - from django.http import Http404 - from django import forms - from django.forms.models import inlineformset_factory, BaseInlineFormSet --from django.core import serializers --import hashlib - - from django.core.mail import send_mail - --from datetime import datetime - import time - - from gestioncof.decorators import cof_required, buro_required --from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution --from bda.algorithm import Algorithm -+from bda2.models import Spectacle, Participant, ChoixSpectacle, Attribution -+from bda2.algorithm import Algorithm - - class BaseBdaFormSet(BaseInlineFormSet): - def clean(self): -@@ -37,7 +33,7 @@ class BaseBdaFormSet(BaseInlineFormSet): - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.") - spectacles.append(spectacle) - --@cof_required -+@buro_required - def etat_places(request): - spectacles1 = ChoixSpectacle.objects.all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.filter(double = True).all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) -@@ -46,93 +42,47 @@ def etat_places(request): - total = 0 - for spectacle in spectacles: - spectacle.total = 0 -- spectacle.ratio = -1.0 - spectacles_dict[spectacle.id] = spectacle - for spectacle in spectacles1: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] -- spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - for spectacle in spectacles2: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] -- spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - return render(request, "etat-places.html", {"spectacles": spectacles, "total": total}) - --def _hash_queryset(queryset): -- data = serializers.serialize("json", queryset) -- hasher = hashlib.sha256() -- hasher.update(data) -- return hasher.hexdigest() -- --@cof_required --def places(request): -- participant, created = Participant.objects.get_or_create(user = request.user) -- places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() -- total = sum([place.spectacle.price for place in places]) -- filtered_places = [] -- places_dict = {} -- spectacles = [] -- dates = [] -- warning = False -- for place in places: -- if place.spectacle in spectacles: -- places_dict[place.spectacle].double = True -- else: -- place.double = False -- places_dict[place.spectacle] = place -- spectacles.append(place.spectacle) -- filtered_places.append(place) -- date = place.spectacle.date.date() -- if date in dates: -- warning = True -- else: -- dates.append(date) -- return render(request, "resume_places.html", -- {"participant": participant, -- "places": filtered_places, -- "total": total, -- "warning": warning}) -- - @cof_required - def inscription(request): -- if datetime.now() > datetime(2013, 10, 6, 23, 59): -- participant, created = Participant.objects.get_or_create(user = request.user) -- choices = participant.choixspectacle_set.order_by("priority").all() -- return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 7 octobre !", "choices": choices}) -+ if time.time() > 1354921200: -+ return render(request, "error.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 6 octobre dans la soirée "}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user = request.user) - success = False -- stateerror = False - if request.method == "POST": -- dbstate = _hash_queryset(participant.choixspectacle_set.all()) -- if "dbstate" in request.POST and dbstate != request.POST["dbstate"]: -- stateerror = True -+ formset = BdaFormSet(request.POST, instance = participant) -+ if formset.is_valid(): -+ #ChoixSpectacle.objects.filter(participant = participant).delete() -+ formset.save() -+ success = True - formset = BdaFormSet(instance = participant) -- else: -- formset = BdaFormSet(request.POST, instance = participant) -- if formset.is_valid(): -- #ChoixSpectacle.objects.filter(participant = participant).delete() -- formset.save() -- success = True -- formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(instance = participant) -- dbstate = _hash_queryset(participant.choixspectacle_set.all()) - total_price = 0 - for choice in participant.choixspectacle_set.all(): - total_price += choice.spectacle.price - if choice.double: total_price += choice.spectacle.price -- return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) -+ return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price}) -+ -+Spectacle.deficit = lambda x: (x.slots-x.nrequests)*x.price - - def do_tirage(request): - form = TokenForm(request.POST) - if not form.is_valid(): - return tirage(request) -- start = time.time() - data = {} -- shows = Spectacle.objects.select_related().all() -+ shows = Spectacle.objects.all() - members = Participant.objects.all() -- choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() -+ choices = ChoixSpectacle.objects.all() - algo = Algorithm(shows, members, choices) - results = algo(form.cleaned_data["token"]) - total_slots = 0 -@@ -149,8 +99,8 @@ def do_tirage(request): - total_sold = 0 - total_deficit = 0 - opera_deficit = 0 -- for (show, members, _) in results: -- deficit = (show.slots - len(members)) * show.price -+ for show in shows: -+ deficit = show.deficit() - total_sold += show.slots * show.price - if deficit >= 0: - if u"Opéra" in show.location.name: -@@ -159,23 +109,18 @@ def do_tirage(request): - data["total_sold"] = total_sold - total_deficit - data["total_deficit"] = total_deficit - data["opera_deficit"] = opera_deficit -- data["duration"] = time.time() - start - if request.user.is_authenticated(): - members2 = {} -- members_uniq = {} # Participant objects are not shared accross spectacle results, -- # So assign a single object for each Participant id - for (show, members, _) in results: - for (member, _, _, _) in members: -- if member.id not in members_uniq: -- members_uniq[member.id] = member -+ if member not in members2: - members2[member] = [] - member.total = 0 -- member = members_uniq[member.id] - members2[member].append(show) - member.total += show.price - members2 = members2.items() - data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name) -- if False and request.user.username in ["seguin", "harazi"]: -+ if False and request.user.username == "seguin": - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: -@@ -220,7 +165,7 @@ Je souhaite revendre %s pour %s le %s (% - Contactez moi par email si vous êtes intéressés ! - - %s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email) -- send_mail("%s" % spectacle, mail, -+ send_mail("Revente de place: %s" % spectacle, mail, - request.user.email, ["bda-revente@lists.ens.fr"], - fail_silently = True) - return render(request, "bda-success.html", {"show": spectacle, "places": places}) -Only in .: views.py~ diff --git a/bda2/migrations/0001_initial.py b/bda2/migrations/0001_initial.py deleted file mode 100644 index 450e1607..00000000 --- a/bda2/migrations/0001_initial.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Attribution', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('given', models.BooleanField(default=False, verbose_name='Donn\xe9e')), - ], - ), - migrations.CreateModel( - name='ChoixSpectacle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('priority', models.PositiveIntegerField(verbose_name=b'Priorit\xc3\xa9')), - ('double', models.BooleanField(default=False, verbose_name=b'Deux places1')), - ('autoquit', models.BooleanField(default=False, verbose_name=b'Abandon2')), - ], - options={ - 'ordering': ('priority',), - 'verbose_name': 'voeu', - 'verbose_name_plural': 'voeux', - }, - ), - migrations.CreateModel( - name='Participant', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('paid', models.BooleanField(default=False, verbose_name='A pay\xe9')), - ('paymenttype', models.CharField(blank=True, max_length=6, verbose_name='Moyen de paiement', choices=[(b'cash', 'Cash'), (b'cb', b'CB'), (b'cheque', 'Ch\xe8que'), (b'autre', 'Autre')])), - ], - ), - migrations.CreateModel( - name='Salle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=300, verbose_name=b'Nom')), - ('address', models.TextField(verbose_name=b'Adresse')), - ], - ), - migrations.CreateModel( - name='Spectacle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=300, verbose_name=b'Titre')), - ('date', models.DateTimeField(verbose_name=b'Date & heure')), - ('description', models.TextField(verbose_name=b'Description', blank=True)), - ('slots_description', models.TextField(verbose_name=b'Description des places', blank=True)), - ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)), - ('slots', models.IntegerField(verbose_name=b'Places')), - ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')), - ('location', models.ForeignKey(to='bda2.Salle')), - ], - options={ - 'ordering': ('priority', 'date', 'title'), - 'verbose_name': 'Spectacle', - }, - ), - migrations.AddField( - model_name='participant', - name='attributions', - field=models.ManyToManyField(related_name='attributed_to', through='bda2.Attribution', to='bda2.Spectacle'), - ), - migrations.AddField( - model_name='participant', - name='choices', - field=models.ManyToManyField(related_name='chosen_by', through='bda2.ChoixSpectacle', to='bda2.Spectacle'), - ), - migrations.AddField( - model_name='participant', - name='user', - field=models.OneToOneField(related_name='participants2', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='choixspectacle', - name='participant', - field=models.ForeignKey(to='bda2.Participant'), - ), - migrations.AddField( - model_name='choixspectacle', - name='spectacle', - field=models.ForeignKey(related_name='participants', to='bda2.Spectacle'), - ), - migrations.AddField( - model_name='attribution', - name='participant', - field=models.ForeignKey(to='bda2.Participant'), - ), - migrations.AddField( - model_name='attribution', - name='spectacle', - field=models.ForeignKey(related_name='attribues', to='bda2.Spectacle'), - ), - migrations.AlterUniqueTogether( - name='choixspectacle', - unique_together=set([('participant', 'spectacle')]), - ), - ] diff --git a/bda2/migrations/__init__.py b/bda2/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/bda2/models.py b/bda2/models.py deleted file mode 100644 index c9fefe6e..00000000 --- a/bda2/models.py +++ /dev/null @@ -1,78 +0,0 @@ -# coding: utf-8 - -import calendar - -from django.db import models -from django.contrib.auth.models import User -from django.utils.translation import ugettext_lazy as _ -from django.db.models.signals import post_save - -class Salle (models.Model): - name = models.CharField ("Nom", max_length = 300) - address = models.TextField ("Adresse") - - def __unicode__ (self): - return self.name - -class Spectacle (models.Model): - title = models.CharField ("Titre", max_length = 300) - date = models.DateTimeField ("Date & heure") - location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank = True) - slots_description = models.TextField ("Description des places", blank = True) - price = models.FloatField("Prix d'une place", blank = True) - slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default = 1000) - - class Meta: - verbose_name = "Spectacle" - ordering = ("priority", "date","title",) - - def __repr__ (self): - return u"[%s]" % self.__unicode__() - - def timestamp(self): - return "%d" % calendar.timegm(self.date.utctimetuple()) - - def date_no_seconds(self): - return self.date.strftime('%d %b %Y %H:%M') - - def __unicode__ (self): - return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) - -PAYMENT_TYPES = ( -("cash",u"Cash"), -("cb","CB"), -("cheque",u"Chèque"), -("autre",u"Autre"), -) - -class Participant (models.Model): - user = models.OneToOneField(User, related_name = "participants2") - choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by") - attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to") - paid = models.BooleanField (u"A payé", default = False) - paymenttype = models.CharField(u"Moyen de paiement", max_length = 6, choices = PAYMENT_TYPES, blank = True) - - def __unicode__ (self): - return u"%s" % (self.user) - -class ChoixSpectacle (models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "participants") - priority = models.PositiveIntegerField("Priorité") - double = models.BooleanField("Deux places1",default=False) - autoquit = models.BooleanField("Abandon2",default=False) - class Meta: - ordering = ("priority",) - unique_together = (("participant", "spectacle",),) - verbose_name = "voeu" - verbose_name_plural = "voeux" - -class Attribution (models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "attribues") - given = models.BooleanField(u"Donnée", default = False) - - def __unicode__ (self): - return u"%s -- %s" % (self.participant, self.spectacle) diff --git a/bda2/static/css/bda.css b/bda2/static/css/bda.css deleted file mode 100644 index 8851eeee..00000000 --- a/bda2/static/css/bda.css +++ /dev/null @@ -1,10 +0,0 @@ -form#tokenform {text-align: center; font-size: 2em;} -label {margin-right: 10px; vertical-align: top;} -form#tokenform textarea {font-size: 2em; width: 350px; height: 200px; font-family: 'Droif Serif', serif;} -input {width: 400px; font-size: 2em;} -ul.losers {display: inline; margin: 0; padding: 0;} -ul.losers li {display: inline;} -span.details {font-size: 0.7em;} -table {border: 1px solid black; border-collapse: collapse;} -td {border: 1px solid black; padding: 2px;} -.attribresult {margin: 10px 0px;} diff --git a/bda2/templates/bda-attrib-extra.html b/bda2/templates/bda-attrib-extra.html deleted file mode 100644 index c2c266d2..00000000 --- a/bda2/templates/bda-attrib-extra.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "bda-attrib.html" %} - -{% block extracontent %} - -

Attribution (détails)

-

Token : {{ token }}

-

Placés : {{ total_slots }} ; Déçus : {{ total_losers }}

- - -{% for member, shows in members2 %} - - - - - - -{% for show in shows %} - - - - - - -{% endfor %} -{% endfor %} -
{{ member.user.get_full_name }}{{ member.user.email }}Total: {{ member.total }}€
{{ show }}
-{% endblock %} diff --git a/bda2/templates/bda-attrib.html b/bda2/templates/bda-attrib.html deleted file mode 100644 index 8390bd03..00000000 --- a/bda2/templates/bda-attrib.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "base_title.html" %} -{% load staticfiles %} - -{% block extra_head %} - -{% endblock %} - -{% block realcontent %} - -

Attribution

-

Token : {{ token }}

-

Placés : {{ total_slots }} ; Déçus : {{ total_losers }}

-{% if user.profile.is_buro %}

Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €

{% endif %} - -{% for show, members, losers in results %} -
-

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

-

-{{ show.nrequests }} demandes pour {{ show.slots }} places -{{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }}€ de déficit{% endif %} -

-Places : -
    -{% for member, rank, origrank, double in members %} -
  • {{ member.user.get_full_name }} (souhait {{ origrank }} — rang {{ rank }})
  • -{% endfor %} -
-Déçus : -{% if not losers %}/{% else %} -
    -{% for member, rank, origrank, double in losers %} -{% if not forloop.first %} ; {% endif %} -
  • {{ member.user.get_full_name }} (souhait {{ origrank }} — rang {{ rank }})
  • -{% endfor %} -
-{% endif %} -
-{% endfor %} -{% block extracontent %} -{% endblock %} -{% endblock %} diff --git a/bda2/templates/bda-emails.html b/bda2/templates/bda-emails.html deleted file mode 100644 index 39744ae1..00000000 --- a/bda2/templates/bda-emails.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

{{ spectacle }}

- -{% endblock %} diff --git a/bda2/templates/bda-notpaid.html b/bda2/templates/bda-notpaid.html deleted file mode 100644 index 10b272d8..00000000 --- a/bda2/templates/bda-notpaid.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Nope

-

Avant de revendre des places, il faut aller les payer !

-{% endblock %} diff --git a/bda2/templates/bda-revente.html b/bda2/templates/bda-revente.html deleted file mode 100644 index 82ed80fe..00000000 --- a/bda2/templates/bda-revente.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base_title.html" %} -{% load staticfiles %} - -{% block extra_head %} - -{% endblock %} - -{% block realcontent %} - -

Revente de place

-
- {% csrf_token %} -{% if form.spectacle.errors %}
  • Sélectionnez un spetacle
{% endif %} -

- -Bonjour,
-
-Je souhaite revendre {{ form.count }} place(s) pour {{ form.spectacle }}.
-Contactez-moi par email si vous êtes intéressé !
-
-{{ user.get_full_name }} ({{ user.email }}) -
-

- -
-{% endblock %} diff --git a/bda2/templates/bda-success.html b/bda2/templates/bda-success.html deleted file mode 100644 index ebcc87a7..00000000 --- a/bda2/templates/bda-success.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "base_title.html" %} -{% load staticfiles %} - -{% block extra_head %} - -{% endblock %} - -{% block realcontent %} - -

Revente de place

-

Votre offre de revente de {{ places }} pour {{ show.title }} le {{ show.date_no_seconds }} ({{ show.location }}) à {{ show.price }}€ a bien été envoyée.

-{% endblock %} diff --git a/bda2/templates/bda-token.html b/bda2/templates/bda-token.html deleted file mode 100644 index cbe72a76..00000000 --- a/bda2/templates/bda-token.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Tirage au sort du BdA

-
- {% csrf_token %} - La graine : -
- {{ form.token }} -
- -
-{% endblock %} diff --git a/bda2/templates/bda-unpaid.html b/bda2/templates/bda-unpaid.html deleted file mode 100644 index 5596dd82..00000000 --- a/bda2/templates/bda-unpaid.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Impayés

- -{% endblock %} diff --git a/bda2/templates/etat-places.html b/bda2/templates/etat-places.html deleted file mode 100644 index 086ca648..00000000 --- a/bda2/templates/etat-places.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Etat des inscriptions BDA

- - Total : {{ total }} demandes -{% endblock %} diff --git a/bda2/templates/inscription-bda.html b/bda2/templates/inscription-bda.html deleted file mode 100644 index 933f087a..00000000 --- a/bda2/templates/inscription-bda.html +++ /dev/null @@ -1,116 +0,0 @@ -{% extends "base_title.html" %} - -{% block extra_head %} - - - - - -{% endblock %} - -{% block realcontent %} - - -

Inscription au tirage au sort du BDA

- {% if success %} -

Votre inscription a été mise à jour avec succès !

- {% endif %} -
- {% csrf_token %} - {% include "inscription-formset.html" %} - - - - Prix total actuel : {{ total_price }}€ -
-

- 1: demander deux places pour ce spectable
- 2: abandonner une place si impossible d'en obtenir une seconde pour ce spectacle (si vous avez coché l'option Deux places pour ce spectacle)
- 3: cette liste de vœu est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque vœu
-

-
-{% endblock %} diff --git a/bda2/templates/inscription-formset.html b/bda2/templates/inscription-formset.html deleted file mode 100644 index 04b68a6b..00000000 --- a/bda2/templates/inscription-formset.html +++ /dev/null @@ -1,40 +0,0 @@ -{{ formset.non_form_errors.as_ul }} - -{{ formset.management_form }} -{% for form in formset.forms %} - {% if forloop.first %} - - {% for field in form.visible_fields %} - {% if field.name != "DELETE" and field.name != "priority" %} - - {% endif %} - {% endfor %} - - - - {% endif %} - - {% for field in form.visible_fields %} - {% if field.name != "DELETE" and field.name != "priority" %} - - {% endif %} - {% endfor %} - - -{% endfor %} - -
{{ field.label|safe|capfirst }}3
- {% if forloop.first %} - {{ form.non_field_errors }} - {% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %} - {% endif %} - {{ field.errors.as_ul }} - {{ field }} -
- - - - -
-
-
diff --git a/bda2/templates/spectacle_list.html b/bda2/templates/spectacle_list.html deleted file mode 100644 index 956037f8..00000000 --- a/bda2/templates/spectacle_list.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Spectacles

- -{% endblock %} diff --git a/bda2/tests.py b/bda2/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/bda2/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" - -from django.test import TestCase - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.assertEqual(1 + 1, 2) diff --git a/bda2/views.py b/bda2/views.py deleted file mode 100644 index 93d54f62..00000000 --- a/bda2/views.py +++ /dev/null @@ -1,248 +0,0 @@ -# coding: utf-8 - -from django.contrib.auth.models import User -from django.shortcuts import render, get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.db import models -from django.http import Http404 -from django import forms -from django.forms.models import inlineformset_factory, BaseInlineFormSet -from django.core import serializers -import hashlib - -from django.core.mail import send_mail - -from datetime import datetime -import time - -from gestioncof.decorators import cof_required, buro_required -from bda2.models import Spectacle, Participant, ChoixSpectacle, Attribution -from bda2.algorithm import Algorithm - -class BaseBdaFormSet(BaseInlineFormSet): - def clean(self): - """Checks that no two articles have the same title.""" - super(BaseBdaFormSet, self).clean() - if any(self.errors): - # Don't bother validating the formset unless each form is valid on its own - return - spectacles = [] - for i in range(0, self.total_form_count()): - form = self.forms[i] - if not form.cleaned_data: - continue - spectacle = form.cleaned_data['spectacle'] - delete = form.cleaned_data['DELETE'] - if not delete and spectacle in spectacles: - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.") - spectacles.append(spectacle) - -@cof_required -def etat_places(request): - spectacles1 = ChoixSpectacle.objects.all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.filter(double = True).all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles = Spectacle.objects.all() - spectacles_dict = {} - total = 0 - for spectacle in spectacles: - spectacle.total = 0 - spectacle.ratio = 0.0 - spectacles_dict[spectacle.id] = spectacle - for spectacle in spectacles1: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - for spectacle in spectacles2: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - return render(request, "etat-places.html", {"spectacles": spectacles, "total": total}) - -def _hash_queryset(queryset): - data = serializers.serialize("json", queryset) - hasher = hashlib.sha256() - hasher.update(data) - return hasher.hexdigest() - -@cof_required -def places(request): - participant, created = Participant.objects.get_or_create(user = request.user) - places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() - total = sum([place.spectacle.price for place in places]) - filtered_places = [] - places_dict = {} - spectacles = [] - dates = [] - warning = False - for place in places: - if place.spectacle in spectacles: - places_dict[place.spectacle].double = True - else: - place.double = False - places_dict[place.spectacle] = place - spectacles.append(place.spectacle) - filtered_places.append(place) - date = place.spectacle.date.date() - if date in dates: - warning = True - else: - dates.append(date) - return render(request, "resume_places.html", - {"participant": participant, - "places": filtered_places, - "total": total, - "warning": warning}) - -@cof_required -def inscription(request): - if datetime.now() > datetime(2016, 1, 17, 12, 00): - participant, created = Participant.objects.get_or_create(user = request.user) - choices = participant.choixspectacle_set.order_by("priority").all() - return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 17 janvier !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user = request.user) - success = False - stateerror = False - if request.method == "POST": - dbstate = _hash_queryset(participant.choixspectacle_set.all()) - if "dbstate" in request.POST and dbstate != request.POST["dbstate"]: - stateerror = True - formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(request.POST, instance = participant) - if formset.is_valid(): - #ChoixSpectacle.objects.filter(participant = participant).delete() - formset.save() - success = True - formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(instance = participant) - dbstate = _hash_queryset(participant.choixspectacle_set.all()) - total_price = 0 - for choice in participant.choixspectacle_set.all(): - total_price += choice.spectacle.price - if choice.double: total_price += choice.spectacle.price - return render(request, "inscription-bda2.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) - -def do_tirage(request): - form = TokenForm(request.POST) - if not form.is_valid(): - return tirage(request) - start = time.time() - data = {} - shows = Spectacle.objects.select_related().all() - members = Participant.objects.all() - choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() - algo = Algorithm(shows, members, choices) - results = algo(form.cleaned_data["token"]) - total_slots = 0 - total_losers = 0 - for (_, members, losers) in results: - total_slots += len(members) - total_losers += len(losers) - data["total_slots"] = total_slots - data["total_losers"] = total_losers - data["shows"] = shows - data["token"] = form.cleaned_data["token"] - data["members"] = members - data["results"] = results - total_sold = 0 - total_deficit = 0 - opera_deficit = 0 - for (show, members, _) in results: - deficit = (show.slots - len(members)) * show.price - total_sold += show.slots * show.price - if deficit >= 0: - if u"Opéra" in show.location.name: - opera_deficit += deficit - total_deficit += deficit - data["total_sold"] = total_sold - total_deficit - data["total_deficit"] = total_deficit - data["opera_deficit"] = opera_deficit - data["duration"] = time.time() - start - if request.user.is_authenticated(): - members2 = {} - members_uniq = {} # Participant objects are not shared accross spectacle results, - # So assign a single object for each Participant id - for (show, members, _) in results: - for (member, _, _, _) in members: - if member.id not in members_uniq: - members_uniq[member.id] = member - members2[member] = [] - member.total = 0 - member = members_uniq[member.id] - members2[member].append(show) - member.total += show.price - members2 = members2.items() - data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name) - if False and request.user.username in ["seguin", "harazi", "fromherz", "mpepin"]: - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: - attrib = Attribution(spectacle = show, participant = member) - attrib.save() - return render(request, "bda-attrib-extra.html", data) - else: - return render(request, "bda-attrib.html", data) - -class TokenForm(forms.Form): - token = forms.CharField(widget = forms.widgets.Textarea()) - -@login_required -def tirage(request): - if request.POST: - form = TokenForm(request.POST) - if form.is_valid(): - return do_tirage(request) - else: - form = TokenForm() - return render(request, "bda-token.html", {"form": form}) - -class SpectacleModelChoiceField(forms.ModelChoiceField): - def label_from_instance(self, obj): - return u"%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), obj.location, obj.price) - -class ResellForm(forms.Form): - count = forms.ChoiceField(choices = (("1","1"),("2","2"),)) - spectacle = SpectacleModelChoiceField(queryset = Spectacle.objects.none()) - - def __init__(self, participant, *args, **kwargs): - super(ResellForm, self).__init__(*args, **kwargs) - self.fields['spectacle'].queryset = participant.attributions.all().distinct() - -def do_resell(request, form): - spectacle = form.cleaned_data["spectacle"] - count = form.cleaned_data["count"] - places = "2 places" if count == "2" else "une place" - mail = u"""Bonjour, - -Je souhaite revendre %s pour %s le %s (%s) à %.02f€. -Contactez moi par email si vous êtes intéressés ! - -%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email) - send_mail("%s" % spectacle, mail, - request.user.email, ["bda-revente@lists.ens.fr"], - fail_silently = True) - return render(request, "bda-success.html", {"show": spectacle, "places": places}) - -@login_required -def revente(request): - participant, created = Participant.objects.get_or_create(user = request.user) - if not participant.paid: - return render(request, "bda-notpaid.html", {}) - if request.POST: - form = ResellForm(participant, request.POST) - if form.is_valid(): - return do_resell(request, form) - else: - form = ResellForm(participant) - return render(request, "bda-revente.html", {"form": form}) - -@buro_required -def spectacle(request, spectacle_id): - spectacle = get_object_or_404(Spectacle, id = spectacle_id) - return render(request, "bda-emails.html", {"spectacle": spectacle}) - -@buro_required -def unpaid(request): - return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()}) diff --git a/bda3/__init__.py b/bda3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/bda3/admin.py b/bda3/admin.py deleted file mode 100644 index 26b0beed..00000000 --- a/bda3/admin.py +++ /dev/null @@ -1,180 +0,0 @@ -# coding: utf-8 - -from django.core.mail import send_mail -from django.contrib.contenttypes.models import ContentType - -from django.contrib import admin -from django.db.models import Sum, Count -from bda3.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution - -class ChoixSpectacleInline(admin.TabularInline): - model = ChoixSpectacle - sortable_field_name = "priority" - -class AttributionInline(admin.TabularInline): - model = Attribution - -class ParticipantAdmin(admin.ModelAdmin): - #inlines = [ChoixSpectacleInline] - inlines = [AttributionInline] - def get_queryset(self, request): - return Participant.objects.annotate(nb_places = Count('attributions'), - total = Sum('attributions__price')) - def nb_places(self, obj): - return obj.nb_places - nb_places.admin_order_field = "nb_places" - nb_places.short_description = "Nombre de places" - def total(self, obj): - tot = obj.total - if tot: return u"%.02f €" % tot - else: return u"0 €" - total.admin_order_field = "total" - total.short_description = "Total à payer" - list_display = ("user", "nb_places", "total", "paid", "paymenttype") - list_filter = ("paid",) - search_fields = ('user__username', 'user__first_name', 'user__last_name') - actions = ['send_attribs',] - actions_on_bottom = True - list_per_page = 400 - - def send_choices(self, request, queryset): - for member in queryset.all(): - choices = member.choixspectacle_set.order_by('priority').all() - if len(choices) == 0: - continue - mail = u"""Cher(e) %s, -Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""" % member.user.get_full_name() - next_rank = 1 - member_shows = {} - for choice in choices: - if choice.spectacle in member_shows: continue - else: member_shows[choice.spectacle] = True - extra = "" - if choice.double: - extra += u" ; deux places" - if choice.autoquit: - extra += u" ; désistement automatique" - mail += u"- Choix %d : %s%s\n" % (next_rank, choice.spectacle, extra) - next_rank += 1 - mail += u"""\nSi cette liste est incorrecte, merci de nous contacter au plus vite (avant samedi 6 octobre 18h). - -Artistiquement, -Le BdA""" - send_mail ("Choix de spectacles (BdA du COF)", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: - message_bit = u"1 membre a" - plural = "" - else: - message_bit = u"%d membres ont" % count - plural = "s" - self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural)) - send_choices.short_description = u"Envoyer les choix par mail" - - def send_attribs(self, request, queryset): - for member in queryset.all(): - attribs = member.attributions.all() - if len(attribs) == 0: - mail = u"""Cher-e %s, - -Tu t'es inscrit-e pour le troisième tirage au sort du BdA. Nous avons le regret -de t'annoncer que tu n'as pas obtenu de place. - -Nous sommes bien conscients que le nombre de places mises en jeu était -très restreint, mais les premier et deuxième tirages au sort comprenaient -déjà un nombre exceptionnel de places, et nous dépendons des limites -fixées par les théâtres partenaires pour l'obtention de places à tarif réduit. - -Le système de revente des places via les mails BdA-revente reste disponible, -alors surveille tes mails. - -En vous souhaitant une bonne fin de journée, --- -Le Bureau des Arts - -""" - name = member.user.get_full_name() - mail = mail % name - else: - mail = u"""Cher-e %s, - -Tu t'es inscrit-e pour le troisième tirage au sort du BdA. Tu as été -sélectionné-e pour les spectacles suivants : - -%s - -Nous sommes bien conscients que le nombre de places mises en jeu était -très restreint, mais les premier et deuxième tirages au sort comprenaient -déjà un nombre exceptionnel de places, et nous dépendons des limites fixées -par les théâtres partenaires pour l'obtention de places à tarif réduit. - -*Paiement* -L'intégralité de ces places de spectacles est à régler à partir du lundi -11 avril et AVANT le 16 avril, au bureau du COF pendant les -heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h -et 20h). Si vous n'êtes pas disponible cette semaine, prévenez-nous par mail. -Attention : au-delà de cette date, les places pourront être remises en jeu. - -*Mode de retrait des places* -Au moment du paiement, les places pour les spectacles de la Comédie-Française -et pour la Philarmonie vous seront remises. - -Nous vous rappelons que l'obtention de places du BdA vous engage à -respecter les règles de fonctionnement : -http://www.cof.ens.fr/bda/?page_id=1370 - -Le système de revente des places via les mails BdA-revente reste disponible, -directement sur votre compte GestioCOF. - -En vous souhaitant de très beaux spectacles, --- -Le Bureau des Arts - -""" - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib - mail = mail % (name, attribs_text) - - send_mail ("[BdA] Résultats du tirage au sort", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: - message_bit = u"1 membre a" - plural = "" - else: - message_bit = u"%d membres ont" % count - plural = "s" - self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural)) - send_attribs.short_description = u"Envoyer les résultats par mail" - -class AttributionAdmin(admin.ModelAdmin): - def paid(self, obj): - return obj.participant.paid - paid.short_description = 'A payé' - paid.boolean = True - list_display = ("id", "spectacle", "participant", "given", "paid") - search_fields = ('spectacle__title', 'participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - -import autocomplete_light -class ChoixSpectacleAdmin(admin.ModelAdmin): - form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) - list_display = ("participant", "spectacle", "priority", "double", "autoquit") - list_filter = ("double", "autoquit") - search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - -class SpectacleAdmin(admin.ModelAdmin): - model = Spectacle - list_display = ("title", "date", "location", "slots", "price") - list_filter = ("location",) - search_fields = ("title", "location__name") - -admin.site.register(Spectacle, SpectacleAdmin) -admin.site.register(Salle) -admin.site.register(Participant, ParticipantAdmin) -admin.site.register(Attribution, AttributionAdmin) -admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin) diff --git a/bda3/algorithm.py b/bda3/algorithm.py deleted file mode 100644 index 623f9756..00000000 --- a/bda3/algorithm.py +++ /dev/null @@ -1,104 +0,0 @@ -# coding: utf-8 - -from django.conf import settings -from django.db.models import Max - -import random - -class Algorithm(object): - - shows = None - ranks = None - origranks = None - double = None - - def __init__(self, shows, members, choices): - """Initialisation : - - on aggrège toutes les demandes pour chaque spectacle dans - show.requests - - on crée des tables de demandes pour chaque personne, afin de - pouvoir modifier les rankings""" - self.max_group = 2 * choices.aggregate(Max('priority'))['priority__max'] - self.shows = [] - showdict = {} - for show in shows: - show.nrequests = 0 - showdict[show] = show - show.requests = [] - self.shows.append(show) - self.ranks = {} - self.origranks = {} - self.choices = {} - next_rank = {} - member_shows = {} - for member in members: - self.ranks[member] = {} - self.choices[member] = {} - next_rank[member] = 1 - member_shows[member] = {} - for choice in choices: - member = choice.participant - if choice.spectacle in member_shows[member]: continue - else: member_shows[member][choice.spectacle] = True - showdict[choice.spectacle].requests.append(member) - showdict[choice.spectacle].nrequests += 2 if choice.double else 1 - self.ranks[member][choice.spectacle] = next_rank[member] - next_rank[member] += 2 if choice.double else 1 - self.choices[member][choice.spectacle] = choice - for member in members: - self.origranks[member] = dict(self.ranks[member]) - - def IncrementRanks(self, member, currank, increment = 1): - for show in self.ranks[member]: - if self.ranks[member][show] > currank: - self.ranks[member][show] -= increment - - def appendResult(self, l, member, show): - l.append((member, - self.ranks[member][show], - self.origranks[member][show], - self.choices[member][show].double)) - - """ - Pour les 2 Walkyries: c'est Sandefer - - Pour les 4 places pour l'Oratorio c'est Maxence Arutkin - """ - - def __call__(self, seed): - random.seed(seed) - results = [] - shows = sorted(self.shows, key = lambda x: float(x.nrequests) / x.slots, reverse = True) - for show in shows: - # On regroupe tous les gens ayant le même rang - groups = dict([(i, []) for i in range(1, self.max_group + 1)]) - for member in show.requests: - if self.ranks[member][show] == 0: - raise RuntimeError, (member, show.title) - groups[self.ranks[member][show]].append(member) - # On passe à l'attribution - winners = [] - losers = [] - for i in range(1, self.max_group + 1): - group = list(groups[i]) - random.shuffle(group) - for member in group: - if self.choices[member][show].double: # double - if len(winners) + 1 < show.slots: - self.appendResult(winners, member, show) - self.appendResult(winners, member, show) - elif not self.choices[member][show].autoquit and len(winners) < show.slots: - self.appendResult(winners, member, show) - self.appendResult(losers, member, show) - else: - self.appendResult(losers, member, show) - self.appendResult(losers, member, show) - self.IncrementRanks(member, i, 2) - else: # simple - if len(winners) < show.slots: - self.appendResult(winners, member, show) - else: - self.appendResult(losers, member, show) - self.IncrementRanks(member, i) - results.append((show,winners,losers)) - return results diff --git a/bda3/autocomplete_light_registry.py b/bda3/autocomplete_light_registry.py deleted file mode 100644 index 3254b3c8..00000000 --- a/bda3/autocomplete_light_registry.py +++ /dev/null @@ -1,9 +0,0 @@ -import autocomplete_light - -from bda.models import Participant, Spectacle - -autocomplete_light.register(Participant, search_fields=('user__username','user__first_name','user__last_name'), - autocomplete_js_attributes={'placeholder': 'participant...'}) - -autocomplete_light.register(Spectacle, search_fields=('title',), - autocomplete_js_attributes={'placeholder': 'spectacle...'}) diff --git a/bda3/difftobda b/bda3/difftobda deleted file mode 100644 index 70c81735..00000000 --- a/bda3/difftobda +++ /dev/null @@ -1,421 +0,0 @@ -Only in .: .admin.py.swp -Binary files ../bda/__init__.pyc and ./__init__.pyc differ -diff -p -u -r ../bda/admin.py ./admin.py ---- ../bda/admin.py 2013-12-17 10:19:56.000000000 +0100 -+++ ./admin.py 2012-12-08 22:31:46.000000000 +0100 -@@ -4,8 +4,8 @@ from django.core.mail import send_mail - from django.contrib.contenttypes.models import ContentType - - from django.contrib import admin --from django.db.models import Sum, Count --from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution -+from django.db.models import Sum -+from bda3.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution - - class ChoixSpectacleInline(admin.TabularInline): - model = ChoixSpectacle -@@ -17,18 +17,13 @@ class AttributionInline(admin.TabularInl - class ParticipantAdmin(admin.ModelAdmin): - #inlines = [ChoixSpectacleInline] - inlines = [AttributionInline] -- def queryset(self, request): -- return Participant.objects.annotate(nb_places = Count('attributions'), -- total = Sum('attributions__price')) - def nb_places(self, obj): -- return obj.nb_places -- nb_places.admin_order_field = "nb_places" -+ return len(obj.attribution_set.all()) - nb_places.short_description = "Nombre de places" - def total(self, obj): -- tot = obj.total -+ tot = obj.attributions.aggregate(total = Sum('price'))['total'] - if tot: return u"%.02f €" % tot - else: return u"0 €" -- total.admin_order_field = "total" - total.short_description = "Total à payer" - list_display = ("user", "nb_places", "total", "paid", "paymenttype") - list_filter = ("paid",) -@@ -61,7 +56,7 @@ Voici tes choix de spectacles tels que n - Artistiquement, - Le BdA""" - send_mail ("Choix de spectacles (BdA du COF)", mail, -- "bda@ens.fr", [member.user.email], -+ "bda@clipper.ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: -@@ -86,48 +81,41 @@ pour les spectacles suivants : - %s - - *Paiement* --L'intégralité de ces places de spectacles est à régler à partir du jeudi --10 octobre et AVANT le mercredi 23 octobre, au bureau du COF pendant les --heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h --et 20h). Des facilités de paiement sont bien évidemment possibles : nous --pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre --paiement en deux fois. -+Ces spectacles sont à régler avant le lundi 17 décembre, pendant les -+heures de permanences du COF (tous les jours de la semaine entre 12h et -+14h, et entre 18h et 20h). Des facilités de paiement sont bien évidemment -+possibles (encaissement échelonné des chèques). - - *Mode de retrait des places* --Au moment du paiement, une enveloppe vous sera remise, contenant les --places pour l'Opéra de Paris, pour les premiers spectacles de la Comédie --française, certains spectacles du Châtelet et du Théâtre de la Ville. -- --Pour les concerts Radio France, le Théâtre des Champs-Élysées, le théâtre --du Rond-Point, le théâtre de la Colline, le théâtre de l'Athénée, l'IRCAM, --la Cité de la musique et le 104, le Studio-Théâtre de la Comédie --française, les places seront nominatives et à retirer au théâtre le soir --de la représentation au moins une demi-heure avant le début du spectacle. -- --Pour le théâtre de l'Odéon, la salle Richelieu le théâtre du Vieux --colombier de la Comédie française, certains spectacles du théâtre de la --Ville et du théâtre de Châtelet ainsi que pour le théâtre de Chaillot, les --places seront distribuées environ une semaine avant la représentation (un --mail vous en avertira). -- --Nous vous rappelons que l'obtention de places du BdA vous engage à --respecter les règles de fonctionnement : --http://www.cof.ens.fr/bda/?page_id=1370 --Le système de revente des places via les mails BdA-revente sera très --prochainement disponible, directement sur votre compte GestioCOF. -+Pour l'Opéra de Paris, le théâtre de la Colline et le théâtre du Châtelet, -+les places sont à retirer au COF le jour du paiement. -+ -+Pour les concerts Radio France, le théâtre des Champs-Élysées, l'IRCAM -+et le 104, les places seront nominatives et à retirer à la salle le soir de -+la représentation au moins une demi-heure avant le début du spectacle. -+ -+Pour le théâtre de l'Odéon, la Comédie Française, le théâtre de la Ville, -+le théâtre de Chaillot, les places seront distribuées dans vos -+casiers environ une semaine avant la représentation (un mail vous en -+avertira). -+ -+Dans tous les cas, n'hésitez pas à nous contacter si vous avez un doute ! -+ -+Nous profitons aussi de ce message pour vous annoncer qu'un festival de -+courts métrages aura lieu le 21 décembre dans l'école. -+Plus d'informations : http://www.cof.ens.fr/bda/courts. -+ -+Culturellement vôtre, - --En vous souhaitant de très beaux spectacles tout au long de l'année, - -- --Le Bureau des Arts --(Chloé, Emilie, Jaime, Maxime, Olivier) --""" -+Le BdA""" - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib - mail = mail % (name, attribs_text) -- send_mail ("Résultats du tirage au sort", mail, -- "bda@ens.fr", [member.user.email], -+ send_mail ("Places de spectacle (BdA du COF)", mail, -+ "bda@clipper.ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: -@@ -154,13 +142,7 @@ class ChoixSpectacleAdmin(admin.ModelAdm - list_filter = ("double", "autoquit") - search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') - --class SpectacleAdmin(admin.ModelAdmin): -- model = Spectacle -- list_display = ("title", "date", "location", "slots", "price") -- list_filter = ("location",) -- search_fields = ("title", "location__name") -- --admin.site.register(Spectacle, SpectacleAdmin) -+admin.site.register(Spectacle) - admin.site.register(Salle) - admin.site.register(Participant, ParticipantAdmin) - admin.site.register(Attribution, AttributionAdmin) -diff -p -u -r ../bda/algorithm.py ./algorithm.py ---- ../bda/algorithm.py 2013-10-07 14:08:44.000000000 +0200 -+++ ./algorithm.py 2012-10-31 23:01:48.000000000 +0100 -@@ -29,24 +29,25 @@ class Algorithm(object): - self.ranks = {} - self.origranks = {} - self.choices = {} -- next_rank = {} -- member_shows = {} - for member in members: -- self.ranks[member] = {} -- self.choices[member] = {} -- next_rank[member] = 1 -- member_shows[member] = {} -- for choice in choices: -- member = choice.participant -- if choice.spectacle in member_shows[member]: continue -- else: member_shows[member][choice.spectacle] = True -- showdict[choice.spectacle].requests.append(member) -- showdict[choice.spectacle].nrequests += 2 if choice.double else 1 -- self.ranks[member][choice.spectacle] = next_rank[member] -- next_rank[member] += 2 if choice.double else 1 -- self.choices[member][choice.spectacle] = choice -- for member in members: -- self.origranks[member] = dict(self.ranks[member]) -+ ranks = {} -+ member_choices = {} -+ member_shows = {} -+ #next_priority = 1 -+ next_rank = 1 -+ for choice in member.choixspectacle_set.order_by('priority').all(): -+ if choice.spectacle in member_shows: continue -+ else: member_shows[choice.spectacle] = True -+ #assert choice.priority == next_priority -+ #next_priority += 1 -+ showdict[choice.spectacle].requests.append(member) -+ showdict[choice.spectacle].nrequests += 2 if choice.double else 1 -+ ranks[choice.spectacle] = next_rank -+ next_rank += 2 if choice.double else 1 -+ member_choices[choice.spectacle] = choice -+ self.ranks[member] = ranks -+ self.choices[member] = member_choices -+ self.origranks[member] = dict(ranks) - - def IncrementRanks(self, member, currank, increment = 1): - for show in self.ranks[member]: -Only in ../bda: algorithm.pyc -Only in .: difftobda -diff -p -u -r ../bda/models.py ./models.py ---- ../bda/models.py 2013-10-10 10:44:43.000000000 +0200 -+++ ./models.py 2012-10-31 23:12:56.000000000 +0100 -@@ -1,7 +1,5 @@ - # coding: utf-8 - --import calendar -- - from django.db import models - from django.contrib.auth.models import User - from django.utils.translation import ugettext_lazy as _ -@@ -19,7 +17,7 @@ class Spectacle (models.Model): - date = models.DateTimeField ("Date & heure") - location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank = True) -- slots_description = models.TextField ("Description des places", blank = True) -+ #slots_description = models.TextField ("Description des places", blank = True) - price = models.FloatField("Prix d'une place", blank = True) - slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default = 1000) -@@ -31,14 +29,11 @@ class Spectacle (models.Model): - def __repr__ (self): - return u"[%s]" % self.__unicode__() - -- def timestamp(self): -- return "%d" % calendar.timegm(self.date.utctimetuple()) -- - def date_no_seconds(self): - return self.date.strftime('%d %b %Y %H:%M') - - def __unicode__ (self): -- return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) -+ return u"%s - %s @ %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) - - PAYMENT_TYPES = ( - ("cash",u"Cash"), -@@ -48,7 +43,7 @@ PAYMENT_TYPES = ( - ) - - class Participant (models.Model): -- user = models.ForeignKey(User, unique = True) -+ user = models.ForeignKey(User, unique = True, related_name = "participants2") - choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by") - attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to") - paid = models.BooleanField (u"A payé", default = False) -Binary files ../bda/models.pyc and ./models.pyc differ -diff -p -u -r ../bda/views.py ./views.py ---- ../bda/views.py 2014-01-04 21:37:15.000000000 +0100 -+++ ./views.py 2013-02-12 22:03:38.000000000 +0100 -@@ -1,23 +1,19 @@ - # coding: utf-8 - --from django.contrib.auth.models import User - from django.shortcuts import render, get_object_or_404 - from django.contrib.auth.decorators import login_required - from django.db import models - from django.http import Http404 - from django import forms - from django.forms.models import inlineformset_factory, BaseInlineFormSet --from django.core import serializers --import hashlib - - from django.core.mail import send_mail - --from datetime import datetime - import time - - from gestioncof.decorators import cof_required, buro_required --from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution --from bda.algorithm import Algorithm -+from bda3.models import Spectacle, Participant, ChoixSpectacle, Attribution -+from bda3.algorithm import Algorithm - - class BaseBdaFormSet(BaseInlineFormSet): - def clean(self): -@@ -37,7 +33,7 @@ class BaseBdaFormSet(BaseInlineFormSet): - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.") - spectacles.append(spectacle) - --@cof_required -+@buro_required - def etat_places(request): - spectacles1 = ChoixSpectacle.objects.all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.filter(double = True).all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) -@@ -46,93 +42,47 @@ def etat_places(request): - total = 0 - for spectacle in spectacles: - spectacle.total = 0 -- spectacle.ratio = -1.0 - spectacles_dict[spectacle.id] = spectacle - for spectacle in spectacles1: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] -- spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - for spectacle in spectacles2: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] -- spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - return render(request, "etat-places.html", {"spectacles": spectacles, "total": total}) - --def _hash_queryset(queryset): -- data = serializers.serialize("json", queryset) -- hasher = hashlib.sha256() -- hasher.update(data) -- return hasher.hexdigest() -- --@cof_required --def places(request): -- participant, created = Participant.objects.get_or_create(user = request.user) -- places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() -- total = sum([place.spectacle.price for place in places]) -- filtered_places = [] -- places_dict = {} -- spectacles = [] -- dates = [] -- warning = False -- for place in places: -- if place.spectacle in spectacles: -- places_dict[place.spectacle].double = True -- else: -- place.double = False -- places_dict[place.spectacle] = place -- spectacles.append(place.spectacle) -- filtered_places.append(place) -- date = place.spectacle.date.date() -- if date in dates: -- warning = True -- else: -- dates.append(date) -- return render(request, "resume_places.html", -- {"participant": participant, -- "places": filtered_places, -- "total": total, -- "warning": warning}) -- - @cof_required - def inscription(request): -- if datetime.now() > datetime(2013, 10, 6, 23, 59): -- participant, created = Participant.objects.get_or_create(user = request.user) -- choices = participant.choixspectacle_set.order_by("priority").all() -- return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 7 octobre !", "choices": choices}) -+ if time.time() > 1354921200: -+ return render(request, "error.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 6 octobre dans la soirée "}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user = request.user) - success = False -- stateerror = False - if request.method == "POST": -- dbstate = _hash_queryset(participant.choixspectacle_set.all()) -- if "dbstate" in request.POST and dbstate != request.POST["dbstate"]: -- stateerror = True -+ formset = BdaFormSet(request.POST, instance = participant) -+ if formset.is_valid(): -+ #ChoixSpectacle.objects.filter(participant = participant).delete() -+ formset.save() -+ success = True - formset = BdaFormSet(instance = participant) -- else: -- formset = BdaFormSet(request.POST, instance = participant) -- if formset.is_valid(): -- #ChoixSpectacle.objects.filter(participant = participant).delete() -- formset.save() -- success = True -- formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(instance = participant) -- dbstate = _hash_queryset(participant.choixspectacle_set.all()) - total_price = 0 - for choice in participant.choixspectacle_set.all(): - total_price += choice.spectacle.price - if choice.double: total_price += choice.spectacle.price -- return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) -+ return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price}) -+ -+Spectacle.deficit = lambda x: (x.slots-x.nrequests)*x.price - - def do_tirage(request): - form = TokenForm(request.POST) - if not form.is_valid(): - return tirage(request) -- start = time.time() - data = {} -- shows = Spectacle.objects.select_related().all() -+ shows = Spectacle.objects.all() - members = Participant.objects.all() -- choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() -+ choices = ChoixSpectacle.objects.all() - algo = Algorithm(shows, members, choices) - results = algo(form.cleaned_data["token"]) - total_slots = 0 -@@ -149,8 +99,8 @@ def do_tirage(request): - total_sold = 0 - total_deficit = 0 - opera_deficit = 0 -- for (show, members, _) in results: -- deficit = (show.slots - len(members)) * show.price -+ for show in shows: -+ deficit = show.deficit() - total_sold += show.slots * show.price - if deficit >= 0: - if u"Opéra" in show.location.name: -@@ -159,23 +109,18 @@ def do_tirage(request): - data["total_sold"] = total_sold - total_deficit - data["total_deficit"] = total_deficit - data["opera_deficit"] = opera_deficit -- data["duration"] = time.time() - start - if request.user.is_authenticated(): - members2 = {} -- members_uniq = {} # Participant objects are not shared accross spectacle results, -- # So assign a single object for each Participant id - for (show, members, _) in results: - for (member, _, _, _) in members: -- if member.id not in members_uniq: -- members_uniq[member.id] = member -+ if member not in members2: - members2[member] = [] - member.total = 0 -- member = members_uniq[member.id] - members2[member].append(show) - member.total += show.price - members2 = members2.items() - data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name) -- if False and request.user.username in ["seguin", "harazi"]: -+ if False and request.user.username == "seguin": - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: -@@ -220,7 +165,7 @@ Je souhaite revendre %s pour %s le %s (% - Contactez moi par email si vous êtes intéressés ! - - %s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email) -- send_mail("%s" % spectacle, mail, -+ send_mail("Revente de place: %s" % spectacle, mail, - request.user.email, ["bda-revente@lists.ens.fr"], - fail_silently = True) - return render(request, "bda-success.html", {"show": spectacle, "places": places}) -Only in .: views.py~ diff --git a/bda3/migrations/0001_initial.py b/bda3/migrations/0001_initial.py deleted file mode 100644 index 7a7e061b..00000000 --- a/bda3/migrations/0001_initial.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Attribution', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('given', models.BooleanField(default=False, verbose_name='Donn\xe9e')), - ], - ), - migrations.CreateModel( - name='ChoixSpectacle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('priority', models.PositiveIntegerField(verbose_name=b'Priorit\xc3\xa9')), - ('double', models.BooleanField(default=False, verbose_name=b'Deux places1')), - ('autoquit', models.BooleanField(default=False, verbose_name=b'Abandon2')), - ], - options={ - 'ordering': ('priority',), - 'verbose_name': 'voeu', - 'verbose_name_plural': 'voeux', - }, - ), - migrations.CreateModel( - name='Participant', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('paid', models.BooleanField(default=False, verbose_name='A pay\xe9')), - ('paymenttype', models.CharField(blank=True, max_length=6, verbose_name='Moyen de paiement', choices=[(b'cash', 'Cash'), (b'cb', b'CB'), (b'cheque', 'Ch\xe8que'), (b'autre', 'Autre')])), - ], - ), - migrations.CreateModel( - name='Salle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=300, verbose_name=b'Nom')), - ('address', models.TextField(verbose_name=b'Adresse')), - ], - ), - migrations.CreateModel( - name='Spectacle', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=300, verbose_name=b'Titre')), - ('date', models.DateTimeField(verbose_name=b'Date & heure')), - ('description', models.TextField(verbose_name=b'Description', blank=True)), - ('slots_description', models.TextField(verbose_name=b'Description des places', blank=True)), - ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)), - ('slots', models.IntegerField(verbose_name=b'Places')), - ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')), - ('location', models.ForeignKey(to='bda3.Salle')), - ], - options={ - 'ordering': ('priority', 'date', 'title'), - 'verbose_name': 'Spectacle', - }, - ), - migrations.AddField( - model_name='participant', - name='attributions', - field=models.ManyToManyField(related_name='attributed_to', through='bda3.Attribution', to='bda3.Spectacle'), - ), - migrations.AddField( - model_name='participant', - name='choices', - field=models.ManyToManyField(related_name='chosen_by', through='bda3.ChoixSpectacle', to='bda3.Spectacle'), - ), - migrations.AddField( - model_name='participant', - name='user', - field=models.OneToOneField(related_name='participants3', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='choixspectacle', - name='participant', - field=models.ForeignKey(to='bda3.Participant'), - ), - migrations.AddField( - model_name='choixspectacle', - name='spectacle', - field=models.ForeignKey(related_name='participants', to='bda3.Spectacle'), - ), - migrations.AddField( - model_name='attribution', - name='participant', - field=models.ForeignKey(to='bda3.Participant'), - ), - migrations.AddField( - model_name='attribution', - name='spectacle', - field=models.ForeignKey(related_name='attribues', to='bda3.Spectacle'), - ), - migrations.AlterUniqueTogether( - name='choixspectacle', - unique_together=set([('participant', 'spectacle')]), - ), - ] diff --git a/bda3/migrations/__init__.py b/bda3/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/bda3/models.py b/bda3/models.py deleted file mode 100644 index 6ada1be3..00000000 --- a/bda3/models.py +++ /dev/null @@ -1,78 +0,0 @@ -# coding: utf-8 - -import calendar - -from django.db import models -from django.contrib.auth.models import User -from django.utils.translation import ugettext_lazy as _ -from django.db.models.signals import post_save - -class Salle (models.Model): - name = models.CharField ("Nom", max_length = 300) - address = models.TextField ("Adresse") - - def __unicode__ (self): - return self.name - -class Spectacle (models.Model): - title = models.CharField ("Titre", max_length = 300) - date = models.DateTimeField ("Date & heure") - location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank = True) - slots_description = models.TextField ("Description des places", blank = True) - price = models.FloatField("Prix d'une place", blank = True) - slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default = 1000) - - class Meta: - verbose_name = "Spectacle" - ordering = ("priority", "date","title",) - - def __repr__ (self): - return u"[%s]" % self.__unicode__() - - def timestamp(self): - return "%d" % calendar.timegm(self.date.utctimetuple()) - - def date_no_seconds(self): - return self.date.strftime('%d %b %Y %H:%M') - - def __unicode__ (self): - return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) - -PAYMENT_TYPES = ( -("cash",u"Cash"), -("cb","CB"), -("cheque",u"Chèque"), -("autre",u"Autre"), -) - -class Participant (models.Model): - user = models.OneToOneField(User, related_name = "participants3") - choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by") - attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to") - paid = models.BooleanField (u"A payé", default = False) - paymenttype = models.CharField(u"Moyen de paiement", max_length = 6, choices = PAYMENT_TYPES, blank = True) - - def __unicode__ (self): - return u"%s" % (self.user) - -class ChoixSpectacle (models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "participants") - priority = models.PositiveIntegerField("Priorité") - double = models.BooleanField("Deux places1",default=False) - autoquit = models.BooleanField("Abandon2",default=False) - class Meta: - ordering = ("priority",) - unique_together = (("participant", "spectacle",),) - verbose_name = "voeu" - verbose_name_plural = "voeux" - -class Attribution (models.Model): - participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "attribues") - given = models.BooleanField(u"Donnée", default = False) - - def __unicode__ (self): - return u"%s -- %s" % (self.participant, self.spectacle) diff --git a/bda3/static/css/bda.css b/bda3/static/css/bda.css deleted file mode 100644 index 8851eeee..00000000 --- a/bda3/static/css/bda.css +++ /dev/null @@ -1,10 +0,0 @@ -form#tokenform {text-align: center; font-size: 2em;} -label {margin-right: 10px; vertical-align: top;} -form#tokenform textarea {font-size: 2em; width: 350px; height: 200px; font-family: 'Droif Serif', serif;} -input {width: 400px; font-size: 2em;} -ul.losers {display: inline; margin: 0; padding: 0;} -ul.losers li {display: inline;} -span.details {font-size: 0.7em;} -table {border: 1px solid black; border-collapse: collapse;} -td {border: 1px solid black; padding: 2px;} -.attribresult {margin: 10px 0px;} diff --git a/bda3/templates/spectacle_list.html b/bda3/templates/spectacle_list.html deleted file mode 100644 index a4a67998..00000000 --- a/bda3/templates/spectacle_list.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base_title.html" %} - -{% block realcontent %} -

Spectacles

- -{% endblock %} diff --git a/bda3/tests.py b/bda3/tests.py deleted file mode 100644 index 501deb77..00000000 --- a/bda3/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" - -from django.test import TestCase - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.assertEqual(1 + 1, 2) diff --git a/bda3/views.py b/bda3/views.py deleted file mode 100644 index 620f1824..00000000 --- a/bda3/views.py +++ /dev/null @@ -1,249 +0,0 @@ - -# coding: utf-8 - -from django.contrib.auth.models import User -from django.shortcuts import render, get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.db import models -from django.http import Http404 -from django import forms -from django.forms.models import inlineformset_factory, BaseInlineFormSet -from django.core import serializers -import hashlib - -from django.core.mail import send_mail - -from datetime import datetime -import time - -from gestioncof.decorators import cof_required, buro_required -from bda3.models import Spectacle, Participant, ChoixSpectacle, Attribution -from bda3.algorithm import Algorithm - -class BaseBdaFormSet(BaseInlineFormSet): - def clean(self): - """Checks that no two articles have the same title.""" - super(BaseBdaFormSet, self).clean() - if any(self.errors): - # Don't bother validating the formset unless each form is valid on its own - return - spectacles = [] - for i in range(0, self.total_form_count()): - form = self.forms[i] - if not form.cleaned_data: - continue - spectacle = form.cleaned_data['spectacle'] - delete = form.cleaned_data['DELETE'] - if not delete and spectacle in spectacles: - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.") - spectacles.append(spectacle) - -@cof_required -def etat_places(request): - spectacles1 = ChoixSpectacle.objects.all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.filter(double = True).all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles = Spectacle.objects.all() - spectacles_dict = {} - total = 0 - for spectacle in spectacles: - spectacle.total = 0 - spectacle.ratio = -1.0 - spectacles_dict[spectacle.id] = spectacle - for spectacle in spectacles1: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - for spectacle in spectacles2: - spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) - total += spectacle["total"] - return render(request, "etat-places.html", {"spectacles": spectacles, "total": total}) - -def _hash_queryset(queryset): - data = serializers.serialize("json", queryset) - hasher = hashlib.sha256() - hasher.update(data) - return hasher.hexdigest() - -@cof_required -def places(request): - participant, created = Participant.objects.get_or_create(user = request.user) - places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() - total = sum([place.spectacle.price for place in places]) - filtered_places = [] - places_dict = {} - spectacles = [] - dates = [] - warning = False - for place in places: - if place.spectacle in spectacles: - places_dict[place.spectacle].double = True - else: - place.double = False - places_dict[place.spectacle] = place - spectacles.append(place.spectacle) - filtered_places.append(place) - date = place.spectacle.date.date() - if date in dates: - warning = True - else: - dates.append(date) - return render(request, "resume_places.html", - {"participant": participant, - "places": filtered_places, - "total": total, - "warning": warning}) - -@cof_required -def inscription(request): - if datetime.now() > datetime(2016, 4, 10, 11, 59): - participant, created = Participant.objects.get_or_create(user = request.user) - choices = participant.choixspectacle_set.order_by("priority").all() - return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort très bientôt !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user = request.user) - success = False - stateerror = False - if request.method == "POST": - dbstate = _hash_queryset(participant.choixspectacle_set.all()) - if "dbstate" in request.POST and dbstate != request.POST["dbstate"]: - stateerror = True - formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(request.POST, instance = participant) - if formset.is_valid(): - #ChoixSpectacle.objects.filter(participant = participant).delete() - formset.save() - success = True - formset = BdaFormSet(instance = participant) - else: - formset = BdaFormSet(instance = participant) - dbstate = _hash_queryset(participant.choixspectacle_set.all()) - total_price = 0 - for choice in participant.choixspectacle_set.all(): - total_price += choice.spectacle.price - if choice.double: total_price += choice.spectacle.price - return render(request, "inscription-bda3.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) - -def do_tirage(request): - form = TokenForm(request.POST) - if not form.is_valid(): - return tirage(request) - start = time.time() - data = {} - shows = Spectacle.objects.select_related().all() - members = Participant.objects.all() - choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() - algo = Algorithm(shows, members, choices) - results = algo(form.cleaned_data["token"]) - total_slots = 0 - total_losers = 0 - for (_, members, losers) in results: - total_slots += len(members) - total_losers += len(losers) - data["total_slots"] = total_slots - data["total_losers"] = total_losers - data["shows"] = shows - data["token"] = form.cleaned_data["token"] - data["members"] = members - data["results"] = results - total_sold = 0 - total_deficit = 0 - opera_deficit = 0 - for (show, members, _) in results: - deficit = (show.slots - len(members)) * show.price - total_sold += show.slots * show.price - if deficit >= 0: - if u"Opéra" in show.location.name: - opera_deficit += deficit - total_deficit += deficit - data["total_sold"] = total_sold - total_deficit - data["total_deficit"] = total_deficit - data["opera_deficit"] = opera_deficit - data["duration"] = time.time() - start - if request.user.is_authenticated(): - members2 = {} - members_uniq = {} # Participant objects are not shared accross spectacle results, - # So assign a single object for each Participant id - for (show, members, _) in results: - for (member, _, _, _) in members: - if member.id not in members_uniq: - members_uniq[member.id] = member - members2[member] = [] - member.total = 0 - member = members_uniq[member.id] - members2[member].append(show) - member.total += show.price - members2 = members2.items() - data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name) - if False and request.user.username in ["seguin", "harazi", "fromherz", "mpepin"]: - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: - attrib = Attribution(spectacle = show, participant = member) - attrib.save() - return render(request, "bda-attrib-extra.html", data) - else: - return render(request, "bda-attrib.html", data) - -class TokenForm(forms.Form): - token = forms.CharField(widget = forms.widgets.Textarea()) - -@login_required -def tirage(request): - if request.POST: - form = TokenForm(request.POST) - if form.is_valid(): - return do_tirage(request) - else: - form = TokenForm() - return render(request, "bda-token.html", {"form": form}) - -class SpectacleModelChoiceField(forms.ModelChoiceField): - def label_from_instance(self, obj): - return u"%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), obj.location, obj.price) - -class ResellForm(forms.Form): - count = forms.ChoiceField(choices = (("1","1"),("2","2"),)) - spectacle = SpectacleModelChoiceField(queryset = Spectacle.objects.none()) - - def __init__(self, participant, *args, **kwargs): - super(ResellForm, self).__init__(*args, **kwargs) - self.fields['spectacle'].queryset = participant.attributions.all().distinct() - -def do_resell(request, form): - spectacle = form.cleaned_data["spectacle"] - count = form.cleaned_data["count"] - places = "2 places" if count == "2" else "une place" - mail = u"""Bonjour, - -Je souhaite revendre %s pour %s le %s (%s) à %.02f€. -Contactez moi par email si vous êtes intéressés ! - -%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email) - send_mail("%s" % spectacle, mail, - request.user.email, ["bda-revente@lists.ens.fr"], - fail_silently = True) - return render(request, "bda-success.html", {"show": spectacle, "places": places}) - -@login_required -def revente(request): - participant, created = Participant.objects.get_or_create(user = request.user) - if not participant.paid: - return render(request, "bda-notpaid.html", {}) - if request.POST: - form = ResellForm(participant, request.POST) - if form.is_valid(): - return do_resell(request, form) - else: - form = ResellForm(participant) - return render(request, "bda-revente.html", {"form": form}) - -@buro_required -def spectacle(request, spectacle_id): - spectacle = get_object_or_404(Spectacle, id = spectacle_id) - return render(request, "bda-emails.html", {"spectacle": spectacle}) - -@buro_required -def unpaid(request): - return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()}) From 4858fe0fb73a761e1efaf41049695aa4ac6a1559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 1 Jun 2016 16:08:15 +0200 Subject: [PATCH 03/37] Modification des urls --- bda/templates/inscription-bda.html | 2 +- cof/urls.py | 28 +++-------- gestioncof/templates/home.html | 75 +++++++++++++++--------------- 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/bda/templates/inscription-bda.html b/bda/templates/inscription-bda.html index 8ee08dc9..f760f1b1 100644 --- a/bda/templates/inscription-bda.html +++ b/bda/templates/inscription-bda.html @@ -98,7 +98,7 @@ var django = { {% if stateerror %}

Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps

{% endif %} -
+ {% csrf_token %} {% include "inscription-formset.html" %} diff --git a/cof/urls.py b/cof/urls.py index 991fb72f..b5163952 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -42,32 +42,18 @@ urlpatterns = patterns('', url(r'^petitcours/demandes/(?P\d+)$', 'gestioncof.petits_cours_views.details', name = 'petits-cours-demande-details'), url(r'^petitcours/demandes/(?P\d+)/traitement$', 'gestioncof.petits_cours_views.traitement', name = 'petits-cours-demande-traitement'), url(r'^petitcours/demandes/(?P\d+)/retraitement$', 'gestioncof.petits_cours_views.retraitement', name = 'petits-cours-demande-retraitement'), - url(r'^bda/inscription$', 'bda.views.inscription', name = 'bda-tirage-inscription'), - url(r'^bda2/inscription$', 'bda2.views.inscription', name = 'bda2-tirage-inscription'), - url(r'^bda3/inscription$', 'bda3.views.inscription', name = 'bda3-tirage-inscription'), - url(r'^bda/places$', 'bda.views.places', name = "bda-places-attribuees"), - url(r'^bda/places/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), - url(r'^bda2/places$', 'bda2.views.places', name = "bda2-places-attribuees"), - url(r'^bda3/places$', 'bda3.views.places', name = "bda3-places-attribuees"), + + url(r'^bda/inscription/(?P\d+)$', 'bda.views.inscription', name = 'bda-tirage-inscription'), + url(r'^bda/places/(?P\d+)$', 'bda.views.places', name = "bda-places-attribuees"), + url(r'^bda/places/(?P\d+)/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), url(r'^bda/revente$', 'bda.views.revente', name = 'bda-revente'), - url(r'^bda2/revente$', 'bda2.views.revente', name = 'bda2-revente'), - url(r'^bda3/revente$', 'bda3.views.revente', name = 'bda3-revente'), - url(r'^bda/etat-places$', 'bda.views.etat_places', name = 'bda-etat-places'), - url(r'^bda2/etat-places$', 'bda2.views.etat_places', name = 'bda2-etat-places'), - url(r'^bda3/etat-places$', 'bda3.views.etat_places', name = 'bda3-etat-places'), - url(r'^bda/tirage$', 'bda.views.tirage'), - url(r'^bda2/tirage$', 'bda2.views.tirage'), - url(r'^bda3/tirage$', 'bda3.views.tirage'), + url(r'^bda/etat-places/(?P\d+)$', 'bda.views.etat_places', name = 'bda-etat-places'), + url(r'^bda/tirage/(?P\d+)$', 'bda.views.tirage'), url(r'^bda/spectacles/$', ListView.as_view(model = Spectacle), name ="bda-liste-spectacles"), url(r'^bda/spectacles/liste_spectacles.ics$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), url(r'^bda/spectacles/unpaid$', "bda.views.unpaid", name = "bda-unpaid"), url(r'^bda/spectacles/(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), - url(r'^bda/spectacles-2/$', ListView.as_view(model = Spectacle2), name ="bda2-liste-spectacles"), - url(r'^bda/spectacles-2/unpaid$', "bda2.views.unpaid", name = "bda2-unpaid"), - url(r'^bda/spectacles-2/(?P\d+)$', "bda2.views.spectacle", name = "bda2-spectacle"), - url(r'^bda/spectacles-3/$', ListView.as_view(model = Spectacle3), name ="bda3-liste-spectacles"), - url(r'^bda/spectacles-3/unpaid$', "bda3.views.unpaid", name = "bda3-unpaid"), - url(r'^bda/spectacles-3/(?P\d+)$', "bda3.views.spectacle", name = "bda3-spectacle"), + url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), url(r'^event/(?P\d+)$', 'gestioncof.views.event'), url(r'^survey/(?P\d+)/status$', 'gestioncof.views.survey_status'), diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index c47a32e0..5d9fbecc 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -21,62 +21,63 @@ {% endfor %} {% endif %} - - - {% if user.profile.is_cof %} -

BdA

- - {% endif %} - + + {% if user.profile.is_cof %} +

BdA

+ + {% endif %} +

Divers

{% if user.profile.is_buro %}

Administration

{% endif %} -

Pour tout problème : cof@ens.fr.

+

Pour tout problème : cof@ens.fr.

{% endblock %} From 7c3984c6fcfdc3a47a673d79e3df4f36f83c32f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 1 Jun 2016 16:09:09 +0200 Subject: [PATCH 04/37] Modification des vues --- bda/algorithm.py | 7 +------ bda/views.py | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/bda/algorithm.py b/bda/algorithm.py index 623f9756..bce41282 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -59,12 +59,6 @@ class Algorithm(object): self.origranks[member][show], self.choices[member][show].double)) - """ - Pour les 2 Walkyries: c'est Sandefer - - Pour les 4 places pour l'Oratorio c'est Maxence Arutkin - """ - def __call__(self, seed): random.seed(seed) results = [] @@ -102,3 +96,4 @@ class Algorithm(object): self.IncrementRanks(member, i) results.append((show,winners,losers)) return results + diff --git a/bda/views.py b/bda/views.py index 78ac0c83..1971686d 100644 --- a/bda/views.py +++ b/bda/views.py @@ -39,9 +39,10 @@ class BaseBdaFormSet(BaseInlineFormSet): spectacles.append(spectacle) @cof_required -def etat_places(request): - spectacles1 = ChoixSpectacle.objects.filter(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.exclude(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) +def etat_places(request, tirage): + all_spectacles = ChoixSpectacle.objects.filter(tirage = tirage) + spectacles1 = all_spectacles.filter(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) + spectacles2 = all_spectacles.exclude(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) spectacles = Spectacle.objects.all() spectacles_dict = {} total = 0 @@ -66,9 +67,9 @@ def _hash_queryset(queryset): return hasher.hexdigest() @cof_required -def places(request): +def places(request, tirage): participant, created = Participant.objects.get_or_create(user = request.user) - places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() + places = participant.attribution_set.filter(tirage = tirage).order_by("spectacle__date", "spectacle").all() total = sum([place.spectacle.price for place in places]) filtered_places = [] places_dict = {} @@ -95,9 +96,9 @@ def places(request): "warning": warning}) @cof_required -def places_ics(request): +def places_ics(request, tirage): participant, created = Participant.objects.get_or_create(user = request.user) - places = participant.attribution_set.order_by("spectacle__date", "spectacle").all() + places = participant.attribution_set.filter(tirage=tirage).order_by("spectacle__date", "spectacle").all() filtered_places = [] places_dict = {} spectacles = [] @@ -116,12 +117,13 @@ def places_ics(request): "places": filtered_places}, content_type="text/calendar") @cof_required -def inscription(request): - if datetime.now() > datetime(2015, 10, 4, 12, 00) and request.user.username != "seguin": +def inscription(request, tirage): + if datetime.now() > datetime(2025, 10, 4, 12, 00): participant, created = Participant.objects.get_or_create(user = request.user) choices = participant.choixspectacle_set.order_by("priority").all() return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort dans la journée !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double_choice","priority",), formset = BaseBdaFormSet) + BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = + ("spectacle","double_choice","priority"), formset = BaseBdaFormSet) participant, created = Participant.objects.get_or_create(user = request.user) success = False stateerror = False @@ -133,20 +135,22 @@ def inscription(request): else: formset = BdaFormSet(request.POST, instance = participant) if formset.is_valid(): - #ChoixSpectacle.objects.filter(participant = participant).delete() - formset.save() + choix = formset.save(commit=False) + for c in choix: + c.tirage = tirage + c.save() success = True formset = BdaFormSet(instance = participant) else: - formset = BdaFormSet(instance = participant) + formset = BdaFormSet(instance = participant, ) dbstate = _hash_queryset(participant.choixspectacle_set.all()) total_price = 0 - for choice in participant.choixspectacle_set.all(): + for choice in participant.choixspectacle_set.filter(tirage=tirage).all(): total_price += choice.spectacle.price if choice.double: total_price += choice.spectacle.price return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) -def do_tirage(request): +def do_tirage(request, tirage): form = TokenForm(request.POST) if not form.is_valid(): return tirage(request) @@ -154,7 +158,7 @@ def do_tirage(request): data = {} shows = Spectacle.objects.select_related().all() members = Participant.objects.all() - choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() + choices = ChoixSpectacle.objects.filter(tirage=tirage).order_by('participant', 'priority').select_related().all() algo = Algorithm(shows, members, choices) results = algo(form.cleaned_data["token"]) total_slots = 0 @@ -211,11 +215,11 @@ class TokenForm(forms.Form): token = forms.CharField(widget = forms.widgets.Textarea()) @login_required -def tirage(request): +def tirage(request, tirage): if request.POST: form = TokenForm(request.POST) if form.is_valid(): - return do_tirage(request) + return do_tirage(request, tirage) else: form = TokenForm() return render(request, "bda-token.html", {"form": form}) @@ -282,9 +286,9 @@ def unpaid(request): return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()}) @buro_required -def liste_spectacles_ics(request): - spectacles = Spectacle.objects.order_by("date").all() +def liste_spectacles_ics(request, tirage): + spectacles = Spectacle.objects.filter(tirage=tirage).order_by("date").all() for spectacle in spectacles: spectacle.dtend = spectacle.date + timedelta(seconds=7200) return render(request, "liste_spectacles.ics", - {"spectacles": spectacles}, content_type="text/calendar") \ No newline at end of file + {"spectacles": spectacles}, content_type="text/calendar") From 1fc6afca07c583178ef9ae3fd69be697504ca5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 3 Jun 2016 14:16:41 +0200 Subject: [PATCH 05/37] Oubli : suppression de bda{2,3} de INSTALLED_APPS --- cof/settings_dev.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 3246b6e5..401127ef 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -41,8 +41,6 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.admindocs', 'bda', - 'bda2', - 'bda3', 'autocomplete_light', 'captcha', 'django_cas_ng', From 12dfe2031353022ae0798bec1aed8c8282e31cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 3 Jun 2016 14:35:38 +0200 Subject: [PATCH 06/37] Supprime des imports inutiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les application `bda2` et `bda3` n'existent plus, le fichier `urls.py` y faisait encore référence. --- cof/urls.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cof/urls.py b/cof/urls.py index cee7ae39..4f2d7330 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -9,8 +9,6 @@ admin.autodiscover() from django.views.generic.list import ListView from django.views.generic.base import TemplateView from bda.models import Spectacle -from bda2.models import Spectacle as Spectacle2 -from bda3.models import Spectacle as Spectacle3 from gestioncof.petits_cours_views import DemandeListView urlpatterns = patterns('', From 8121dde36a33f56671c58092236b01dc4bcf067d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 3 Jun 2016 14:44:00 +0200 Subject: [PATCH 07/37] =?UTF-8?q?Ajout=20d'une=20ligne=20supprim=C3=A9e=20?= =?UTF-8?q?par=20erreur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bda/views.py b/bda/views.py index c100d128..0f0bbf3d 100644 --- a/bda/views.py +++ b/bda/views.py @@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required from django.db import models from django.http import Http404 from django.core import serializers +from django.forms.models import inlineformset_factory, BaseInlineFormSet import hashlib from django.core.mail import send_mail From ae3677701d6a9dc589a7f4e39c20c9a407bc92dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 4 Jun 2016 13:25:35 +0200 Subject: [PATCH 08/37] Mise en forme - Suppression des espaces autour des signes `=` dans les keyword arguments. Cf [PEP8](https://www.python.org/dev/peps/pep-0008/) - Suppression d'une virgule inutile. --- bda/views.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/bda/views.py b/bda/views.py index 0f0bbf3d..dc91758e 100644 --- a/bda/views.py +++ b/bda/views.py @@ -24,8 +24,8 @@ from bda.forms import BaseBdaFormSet, TokenForm, ResellForm @cof_required def etat_places(request, tirage): all_spectacles = ChoixSpectacle.objects.filter(tirage = tirage) - spectacles1 = all_spectacles.filter(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) - spectacles2 = all_spectacles.exclude(double_choice = "1").all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle')) + spectacles1 = all_spectacles.filter(double_choice="1").all().values('spectacle','spectacle__title').annotate(total=models.Count('spectacle')) + spectacles2 = all_spectacles.exclude(double_choice="1").all().values('spectacle','spectacle__title').annotate(total=models.Count('spectacle')) spectacles = Spectacle.objects.all() spectacles_dict = {} total = 0 @@ -51,8 +51,8 @@ def _hash_queryset(queryset): @cof_required def places(request, tirage): - participant, created = Participant.objects.get_or_create(user = request.user) - places = participant.attribution_set.filter(tirage = tirage).order_by("spectacle__date", "spectacle").all() + participant, created = Participant.objects.get_or_create(user=request.user) + places = participant.attribution_set.filter(tirage=tirage).order_by("spectacle__date", "spectacle").all() total = sum([place.spectacle.price for place in places]) filtered_places = [] places_dict = {} @@ -80,7 +80,7 @@ def places(request, tirage): @cof_required def places_ics(request, tirage): - participant, created = Participant.objects.get_or_create(user = request.user) + participant, created = Participant.objects.get_or_create(user=request.user) places = participant.attribution_set.filter(tirage=tirage).order_by("spectacle__date", "spectacle").all() filtered_places = [] places_dict = {} @@ -102,30 +102,30 @@ def places_ics(request, tirage): @cof_required def inscription(request, tirage): if datetime.now() > datetime(2025, 10, 4, 12, 00): - participant, created = Participant.objects.get_or_create(user = request.user) + participant, created = Participant.objects.get_or_create(user=request.user) choices = participant.choixspectacle_set.order_by("priority").all() return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort dans la journée !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = - ("spectacle","double_choice","priority"), formset = BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user = request.user) + BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, + fields=("spectacle","double_choice","priority"), formset=BaseBdaFormSet) + participant, created = Participant.objects.get_or_create(user=request.user) success = False stateerror = False if request.method == "POST": dbstate = _hash_queryset(participant.choixspectacle_set.all()) if "dbstate" in request.POST and dbstate != request.POST["dbstate"]: stateerror = True - formset = BdaFormSet(instance = participant) + formset = BdaFormSet(instance=participant) else: - formset = BdaFormSet(request.POST, instance = participant) + formset = BdaFormSet(request.POST, instance=participant) if formset.is_valid(): choix = formset.save(commit=False) for c in choix: c.tirage = tirage c.save() success = True - formset = BdaFormSet(instance = participant) + formset = BdaFormSet(instance=participant) else: - formset = BdaFormSet(instance = participant, ) + formset = BdaFormSet(instance=participant) dbstate = _hash_queryset(participant.choixspectacle_set.all()) total_price = 0 for choice in participant.choixspectacle_set.filter(tirage=tirage).all(): @@ -233,7 +233,7 @@ Contactez moi par email si vous êtes intéressé·e·s ! @login_required def revente(request): - participant, created = Participant.objects.get_or_create(user = request.user) + participant, created = Participant.objects.get_or_create(user=request.user) if not participant.paid: return render(request, "bda-notpaid.html", {}) if request.POST: @@ -251,7 +251,7 @@ def spectacle(request, spectacle_id): @buro_required def unpaid(request): - return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()}) + return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid=False).all()}) @buro_required def liste_spectacles_ics(request, tirage): From ac641a5d9535babee359de0326e91166b81d46bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 4 Jun 2016 13:30:48 +0200 Subject: [PATCH 09/37] Suppression de deux lignes vides inutiles --- cof/urls.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cof/urls.py b/cof/urls.py index 4f2d7330..332d9ae6 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -40,7 +40,6 @@ urlpatterns = patterns('', url(r'^petitcours/demandes/(?P\d+)$', 'gestioncof.petits_cours_views.details', name = 'petits-cours-demande-details'), url(r'^petitcours/demandes/(?P\d+)/traitement$', 'gestioncof.petits_cours_views.traitement', name = 'petits-cours-demande-traitement'), url(r'^petitcours/demandes/(?P\d+)/retraitement$', 'gestioncof.petits_cours_views.retraitement', name = 'petits-cours-demande-retraitement'), - url(r'^bda/inscription/(?P\d+)$', 'bda.views.inscription', name = 'bda-tirage-inscription'), url(r'^bda/places/(?P\d+)$', 'bda.views.places', name = "bda-places-attribuees"), url(r'^bda/places/(?P\d+)/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), @@ -51,7 +50,6 @@ urlpatterns = patterns('', url(r'^bda/spectacles/liste_spectacles.ics$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), url(r'^bda/spectacles/unpaid$', "bda.views.unpaid", name = "bda-unpaid"), url(r'^bda/spectacles/(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), - url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), url(r'^event/(?P\d+)$', 'gestioncof.views.event'), url(r'^survey/(?P\d+)/status$', 'gestioncof.views.survey_status'), From 77f678c791f7a658d776036e9d2fe6d438dd01c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 4 Jun 2016 17:57:06 +0200 Subject: [PATCH 10/37] =?UTF-8?q?Ajout=20d'un=20mod=C3=A8le=20et=20nettoya?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout du modèle `Tirage` avec - Un titre / intitulé - Une date de début. - Une date de fin. - La graine, qui peut être nulle au moment ou on crée le tirage. - Formatage du code sur 80 colonnes. - Suppression des espaces autour des signes `=` dans les arguments nommés conformément à [PEP8](https://www.python.org/dev/peps/pep-0008/) --- bda/models.py | 55 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/bda/models.py b/bda/models.py index cd013d0e..9fc66075 100644 --- a/bda/models.py +++ b/bda/models.py @@ -7,6 +7,18 @@ from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ from django.db.models.signals import post_save +class Tirage(models.Model): + title = models.CharField("Titre", max_length=300) + ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") + fermeture = models.DateTimeField("Date et heure de fermerture du tirage") + token = models.TextField("Graine du tirage", blank=True) + + def date_no_seconds(self): + return self.fermeture.strftime('%d %b %Y %H:%M') + + def __unicode__(self): + return u"Tirage au sort du BdA du %s" % (self.date_no_seconds()) + class Salle (models.Model): name = models.CharField ("Nom", max_length = 300) address = models.TextField ("Adresse") @@ -15,15 +27,15 @@ class Salle (models.Model): return self.name class Spectacle (models.Model): - title = models.CharField ("Titre", max_length = 300) + title = models.CharField ("Titre", max_length=300) date = models.DateTimeField ("Date & heure") location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank = True) - slots_description = models.TextField ("Description des places", blank = True) - price = models.FloatField("Prix d'une place", blank = True) + description = models.TextField ("Description", blank=True) + slots_description = models.TextField ("Description des places", blank=True) + price = models.FloatField("Prix d'une place", blank=True) slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default = 1000) - tirage = models.IntegerField ("Tirage") + priority = models.IntegerField ("Priorité", default=1000) + tirage = models.ForeignKey (Tirage) class Meta: verbose_name = "Spectacle" @@ -39,7 +51,8 @@ class Spectacle (models.Model): return self.date.strftime('%d %b %Y %H:%M') def __unicode__ (self): - return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price) + return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), + self.location, self.price) PAYMENT_TYPES = ( ("cash",u"Cash"), @@ -49,11 +62,17 @@ PAYMENT_TYPES = ( ) class Participant (models.Model): - user = models.OneToOneField(User) - choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by") - attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to") - paid = models.BooleanField (u"A payé", default = False) - paymenttype = models.CharField(u"Moyen de paiement", max_length = 6, choices = PAYMENT_TYPES, blank = True) + user = models.ForeignKey(User) + choices = models.ManyToManyField(Spectacle, + through="ChoixSpectacle", + related_name="chosen_by") + attributions = models.ManyToManyField(Spectacle, + through="Attribution", + related_name="attributed_to") + paid = models.BooleanField (u"A payé", default=False) + paymenttype = models.CharField(u"Moyen de paiement", + max_length=6, choices=PAYMENT_TYPES, blank=True) + tirage = models.ForeignKey(Tirage) def __unicode__ (self): return u"%s" % (self.user) @@ -66,10 +85,10 @@ DOUBLE_CHOICES = ( class ChoixSpectacle (models.Model): participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "participants") + spectacle = models.ForeignKey(Spectacle, related_name="participants") priority = models.PositiveIntegerField("Priorité") - double_choice = models.CharField("Nombre de places", default = "1", choices = DOUBLE_CHOICES, max_length = 10) - tirage = models.IntegerField("Tirage") + double_choice = models.CharField("Nombre de places", + default="1", choices=DOUBLE_CHOICES, max_length=10) def get_double(self): return self.double_choice != "1" @@ -87,9 +106,9 @@ class ChoixSpectacle (models.Model): class Attribution (models.Model): participant = models.ForeignKey(Participant) - spectacle = models.ForeignKey(Spectacle, related_name = "attribues") - given = models.BooleanField(u"Donnée", default = False) - tirage = models.IntegerField("Tirage") + spectacle = models.ForeignKey(Spectacle, related_name="attribues") + given = models.BooleanField(u"Donnée", default=False) def __unicode__ (self): return u"%s -- %s" % (self.participant, self.spectacle) + From d9053097936160b6d6859a7885d70d6f59698c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 02:16:14 +0200 Subject: [PATCH 11/37] Mise en forme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Formatage 80 colonnes et, suppression des espaces autour des signes `=` dans les arguments nommés et suppression d'un import inutile. --- bda/forms.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bda/forms.py b/bda/forms.py index 8a652296..d61623db 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -1,7 +1,7 @@ # coding: utf-8 from django import forms -from django.forms.models import inlineformset_factory, BaseInlineFormSet +from django.forms.models import BaseInlineFormSet from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution class BaseBdaFormSet(BaseInlineFormSet): @@ -19,19 +19,21 @@ class BaseBdaFormSet(BaseInlineFormSet): spectacle = form.cleaned_data['spectacle'] delete = form.cleaned_data['DELETE'] if not delete and spectacle in spectacles: - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.") + raise forms.ValidationError("Vous ne pouvez pas vous " + \ + "inscrire deux fois pour le même spectacle.") spectacles.append(spectacle) class TokenForm(forms.Form): - token = forms.CharField(widget = forms.widgets.Textarea()) + token = forms.CharField(widget=forms.widgets.Textarea()) class SpectacleModelChoiceField(forms.ModelChoiceField): def label_from_instance(self, obj): - return u"%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), obj.location, obj.price) + return u"%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), + obj.location, obj.price) class ResellForm(forms.Form): count = forms.ChoiceField(choices = (("1","1"),("2","2"),)) - spectacle = SpectacleModelChoiceField(queryset = Spectacle.objects.none()) + spectacle = SpectacleModelChoiceField(queryset=Spectacle.objects.none()) def __init__(self, participant, *args, **kwargs): super(ResellForm, self).__init__(*args, **kwargs) From fa7de0b7c722381e91a05c2c3142cc694734c287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 02:18:12 +0200 Subject: [PATCH 12/37] =?UTF-8?q?Adaptation=20des=20vues=20aux=20nouveaux?= =?UTF-8?q?=20mod=C3=A8les?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/admin.py | 3 +- bda/views.py | 131 +++++++++++++++++++++++++++++++++------------------ cof/urls.py | 24 ++++++---- 3 files changed, 101 insertions(+), 57 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index bcbc609c..e1788c6b 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib import admin from django.db.models import Sum, Count -from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution +from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution, Tirage class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle @@ -155,3 +155,4 @@ admin.site.register(Salle) admin.site.register(Participant, ParticipantAdmin) admin.site.register(Attribution, AttributionAdmin) admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin) +admin.site.register(Tirage) diff --git a/bda/views.py b/bda/views.py index dc91758e..0789b9ff 100644 --- a/bda/views.py +++ b/bda/views.py @@ -6,27 +6,34 @@ from django.contrib.auth.decorators import login_required from django.db import models from django.http import Http404 from django.core import serializers -from django.forms.models import inlineformset_factory, BaseInlineFormSet +from django.forms.models import inlineformset_factory import hashlib from django.core.mail import send_mail +from django.utils import timezone -from datetime import datetime, timedelta +from datetime import timedelta import time from gestioncof.decorators import cof_required, buro_required from gestioncof.shared import send_custom_mail -from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution +from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution, Tirage from bda.algorithm import Algorithm from bda.forms import BaseBdaFormSet, TokenForm, ResellForm @cof_required -def etat_places(request, tirage): - all_spectacles = ChoixSpectacle.objects.filter(tirage = tirage) - spectacles1 = all_spectacles.filter(double_choice="1").all().values('spectacle','spectacle__title').annotate(total=models.Count('spectacle')) - spectacles2 = all_spectacles.exclude(double_choice="1").all().values('spectacle','spectacle__title').annotate(total=models.Count('spectacle')) - spectacles = Spectacle.objects.all() +def etat_places(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + spectacles1 = ChoixSpectacles.objetcs.filter(tirage=tirage + ).filter(double_choice="1" + ).all().values('spectacle','spectacle__title' + ).annotate(total=models.Count('spectacle')) + spectacles2 = ChoixSpectacles.objetcs.filter(tirage=tirage + ).exclude(double_choice="1" + ).all().values('spectacle','spectacle__title' + ).annotate(total=models.Count('spectacle')) + spectacles = Spectacle.objects.filter(tirage__id=num_tirage).all() spectacles_dict = {} total = 0 for spectacle in spectacles: @@ -35,13 +42,18 @@ def etat_places(request, tirage): spectacles_dict[spectacle.id] = spectacle for spectacle in spectacles1: spectacles_dict[spectacle["spectacle"]].total += spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) + spectacles_dict[spectacle["spectacle"]].ratio = \ + spectacles_dict[spectacle["spectacle"]].total / \ + float(spectacles_dict[spectacle["spectacle"]].slots) total += spectacle["total"] for spectacle in spectacles2: spectacles_dict[spectacle["spectacle"]].total += 2*spectacle["total"] - spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots) + spectacles_dict[spectacle["spectacle"]].ratio = \ + spectacles_dict[spectacle["spectacle"]].total / \ + float(spectacles_dict[spectacle["spectacle"]].slots) total += spectacle["total"] - return render(request, "etat-places.html", {"spectacles": spectacles, "total": total}) + return render(request, "etat-places.html", + {"spectacles": spectacles, "total": total, 'tirage': tirage}) def _hash_queryset(queryset): data = serializers.serialize("json", queryset) @@ -50,9 +62,12 @@ def _hash_queryset(queryset): return hasher.hexdigest() @cof_required -def places(request, tirage): - participant, created = Participant.objects.get_or_create(user=request.user) - places = participant.attribution_set.filter(tirage=tirage).order_by("spectacle__date", "spectacle").all() +def places(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + participant, created = Participant.objects.get_or_create( + user=request.user, tirage=tirage) + places = participant.attribution_set.order_by( + "spectacle__date", "spectacle").all() total = sum([place.spectacle.price for place in places]) filtered_places = [] places_dict = {} @@ -75,13 +90,17 @@ def places(request, tirage): return render(request, "resume_places.html", {"participant": participant, "places": filtered_places, + "tirage": tirage, "total": total, "warning": warning}) @cof_required -def places_ics(request, tirage): - participant, created = Participant.objects.get_or_create(user=request.user) - places = participant.attribution_set.filter(tirage=tirage).order_by("spectacle__date", "spectacle").all() +def places_ics(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + participant, created = Participant.objects.get_or_create( + user=request.user, tirage=tirage) + places = participant.attribution_set.order_by( + "spectacle__date", "spectacle").all() filtered_places = [] places_dict = {} spectacles = [] @@ -100,14 +119,20 @@ def places_ics(request, tirage): "places": filtered_places}, content_type="text/calendar") @cof_required -def inscription(request, tirage): - if datetime.now() > datetime(2025, 10, 4, 12, 00): - participant, created = Participant.objects.get_or_create(user=request.user) +def inscription(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + if timezone.now() > tirage.fermeture: + participant, created = Participant.objects.get_or_create( + user=request.user, tirage=tirage) choices = participant.choixspectacle_set.order_by("priority").all() - return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort dans la journée !", "choices": choices}) + return render(request, "resume_inscription.html", + { "error_title": "C'est fini !", + "error_description": u"Tirage au sort dans la journée !", + "choices": choices}) BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields=("spectacle","double_choice","priority"), formset=BaseBdaFormSet) - participant, created = Participant.objects.get_or_create(user=request.user) + participant, created = Participant.objects.get_or_create( + user=request.user, tirage=tirage) success = False stateerror = False if request.method == "POST": @@ -118,30 +143,35 @@ def inscription(request, tirage): else: formset = BdaFormSet(request.POST, instance=participant) if formset.is_valid(): - choix = formset.save(commit=False) - for c in choix: - c.tirage = tirage - c.save() + formset.save() success = True formset = BdaFormSet(instance=participant) else: formset = BdaFormSet(instance=participant) dbstate = _hash_queryset(participant.choixspectacle_set.all()) total_price = 0 - for choice in participant.choixspectacle_set.filter(tirage=tirage).all(): + for choice in participant.choixspectacle_set.all(): total_price += choice.spectacle.price if choice.double: total_price += choice.spectacle.price - return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror}) + return render(request, "inscription-bda.html", + { "formset": formset, + "success": success, + "total_price": total_price, + "dbstate": dbstate, + 'tirage': tirage, + "stateerror": stateerror}) -def do_tirage(request, tirage): +def do_tirage(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) form = TokenForm(request.POST) if not form.is_valid(): return tirage(request) start = time.time() data = {} - shows = Spectacle.objects.select_related().all() - members = Participant.objects.all() - choices = ChoixSpectacle.objects.filter(tirage=tirage).order_by('participant', 'priority').select_related().all() + shows = Spectacle.objects.filter(tirage=tirage).select_related().all() + members = Participant.objects.filter(tirage=tirage).all() + choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage).order_by( + 'participant', 'priority').select_related().all() algo = Algorithm(shows, members, choices) results = algo(form.cleaned_data["token"]) total_slots = 0 @@ -183,23 +213,23 @@ def do_tirage(request, tirage): members2[member].append(show) member.total += show.price members2 = members2.items() - data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name) + data["members2"] = sorted(members2, key=lambda m: m[0].user.last_name) if False and request.user.username in ["seguin", "harazi","fromherz", "ccadiou"]: Attribution.objects.all().delete() for (show, members, _) in results: for (member, _, _, _) in members: - attrib = Attribution(spectacle = show, participant = member) + attrib = Attribution(spectacle=show, participant=member) attrib.save() return render(request, "bda-attrib-extra.html", data) else: return render(request, "bda-attrib.html", data) @login_required -def tirage(request, tirage): +def tirage(request, tirage_id): if request.POST: form = TokenForm(request.POST) if form.is_valid(): - return do_tirage(request, tirage) + return do_tirage(request, tirage_id) else: form = TokenForm() return render(request, "bda-token.html", {"form": form}) @@ -225,15 +255,19 @@ def do_resell(request, form): Je souhaite revendre %s pour %s le %s (%s) à %.02f€. Contactez moi par email si vous êtes intéressé·e·s ! -%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email) +%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), + spectacle.location, spectacle.price, request.user.get_full_name(), + request.user.email) send_mail("%s" % spectacle, mail, request.user.email, ["bda-revente@lists.ens.fr"], fail_silently = False) return render(request, "bda-success.html", {"show": spectacle, "places": places}) @login_required -def revente(request): - participant, created = Participant.objects.get_or_create(user=request.user) +def revente(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + participant, created = Participant.objects.get_or_create( + user=request.user, tirage=tirage) if not participant.paid: return render(request, "bda-notpaid.html", {}) if request.POST: @@ -242,21 +276,26 @@ def revente(request): return do_resell(request, form) else: form = ResellForm(participant) - return render(request, "bda-revente.html", {"form": form}) + return render(request, "bda-revente.html", {"form": form, 'tirage': tirage}) @buro_required -def spectacle(request, spectacle_id): - spectacle = get_object_or_404(Spectacle, id = spectacle_id) +def spectacle(request, tirage_id, spectacle_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + spectacle = get_object_or_404(Spectacle, id = spectacle_id, tirage=tirage) return render(request, "bda-emails.html", {"spectacle": spectacle}) @buro_required -def unpaid(request): - return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid=False).all()}) +def unpaid(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) + unpaid = Participants.objects.filter(tirage=tirage, paid=False).all() + return render(request, "bda-unpaid.html", {"unpaid": unpaid}) @buro_required -def liste_spectacles_ics(request, tirage): +def liste_spectacles_ics(request, tirage_id): spectacles = Spectacle.objects.filter(tirage=tirage).order_by("date").all() for spectacle in spectacles: spectacle.dtend = spectacle.date + timedelta(seconds=7200) return render(request, "liste_spectacles.ics", - {"spectacles": spectacles}, content_type="text/calendar") + { "spectacles": spectacles, "tirage": tirage}, + content_type="text/calendar") + diff --git a/cof/urls.py b/cof/urls.py index 332d9ae6..6b55e5dd 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -40,16 +40,20 @@ urlpatterns = patterns('', url(r'^petitcours/demandes/(?P\d+)$', 'gestioncof.petits_cours_views.details', name = 'petits-cours-demande-details'), url(r'^petitcours/demandes/(?P\d+)/traitement$', 'gestioncof.petits_cours_views.traitement', name = 'petits-cours-demande-traitement'), url(r'^petitcours/demandes/(?P\d+)/retraitement$', 'gestioncof.petits_cours_views.retraitement', name = 'petits-cours-demande-retraitement'), - url(r'^bda/inscription/(?P\d+)$', 'bda.views.inscription', name = 'bda-tirage-inscription'), - url(r'^bda/places/(?P\d+)$', 'bda.views.places', name = "bda-places-attribuees"), - url(r'^bda/places/(?P\d+)/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), - url(r'^bda/revente$', 'bda.views.revente', name = 'bda-revente'), - url(r'^bda/etat-places/(?P\d+)$', 'bda.views.etat_places', name = 'bda-etat-places'), - url(r'^bda/tirage/(?P\d+)$', 'bda.views.tirage'), - url(r'^bda/spectacles/$', ListView.as_view(model = Spectacle), name ="bda-liste-spectacles"), - url(r'^bda/spectacles/liste_spectacles.ics$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), - url(r'^bda/spectacles/unpaid$', "bda.views.unpaid", name = "bda-unpaid"), - url(r'^bda/spectacles/(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), + + url(r'^bda/inscription/(?P\d+)$', 'bda.views.inscription', name = 'bda-tirage-inscription'), + url(r'^bda/places/(?P\d+)$', 'bda.views.places', name = "bda-places-attribuees"), + url(r'^bda/places/(?P\d+)/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), + url(r'^bda/revente/(?P\d+)$', 'bda.views.revente', name = 'bda-revente'), + url(r'^bda/etat-places/(?P\d+)$', 'bda.views.etat_places', name = 'bda-etat-places'), + url(r'^bda/tirage/(?P\d+)$', 'bda.views.tirage'), + url(r'^bda/spectacles/(?P\d+)/$', lambda tirage_id: ListView(model=Spectacle, + queryset=Spectacle.objects.filter(tirage__id=tirage_id) + ), name ="bda-liste-spectacles"), + url(r'^bda/spectacles/(?P\d+)(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), + url(r'^bda/spectacles/(?P)/liste_spectacles.ics$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), + url(r'^bda/spectacles/unpaid(?P\d+)$', "bda.views.unpaid", name = "bda-unpaid"), + url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), url(r'^event/(?P\d+)$', 'gestioncof.views.event'), url(r'^survey/(?P\d+)/status$', 'gestioncof.views.survey_status'), From 9ad14e7257282005edd8ba37d6844d17782a053e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 02:19:47 +0200 Subject: [PATCH 13/37] Affichage d'un seul tirage sur la page d'accueil --- gestioncof/templates/home.html | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index 5d9fbecc..fe713f61 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -30,22 +30,9 @@
  • Inscription au premier tirage au sort du BdA
  • État des demandes
  • Mes places du premier tirage
  • +
  • Revendre une place du premier tirage

  • - Second tirage -
  • Inscription au deuxième tirage au sort du BdA
  • -
  • État des demandes
  • -
  • Mes places du deuxième tirage
  • -
    - - Troisième tirage -
  • Inscription au troisième tirage au sort du BdA
  • -
  • État des demandes
  • -
  • Mes places du troisième tirage
  • -
    - - Revente -
  • Revendre une place
  • {% endif %} From dfd4fb7d835362e69b4ac72a4267f5bf5a888965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 13:59:24 +0200 Subject: [PATCH 14/37] Tirage utilisable et plus joli MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout de balises `
    ` pour mettre en valeur le token
    - On remplace la condition sur les utilisateurs par le décorateur
      `@buro_required`
    ---
     bda/templates/bda-attrib-extra.html |  3 ++-
     bda/templates/bda-attrib.html       |  3 ++-
     bda/views.py                        | 14 +++++++-------
     3 files changed, 11 insertions(+), 9 deletions(-)
    
    diff --git a/bda/templates/bda-attrib-extra.html b/bda/templates/bda-attrib-extra.html
    index c2c266d2..8ffccf34 100644
    --- a/bda/templates/bda-attrib-extra.html
    +++ b/bda/templates/bda-attrib-extra.html
    @@ -3,7 +3,8 @@
     {% block extracontent %}
     
     

    Attribution (détails)

    -

    Token : {{ token }}

    +

    Token :

    +
    {{ token }}

    Placés : {{ total_slots }} ; Déçus : {{ total_losers }}

    diff --git a/bda/templates/bda-attrib.html b/bda/templates/bda-attrib.html index 22f5786a..f0bfd955 100644 --- a/bda/templates/bda-attrib.html +++ b/bda/templates/bda-attrib.html @@ -8,7 +8,8 @@ {% block realcontent %}

    Attribution

    -

    Token : {{ token }}

    +

    Token :

    +
    {{ token }}

    Placés : {{ total_slots }} ; Déçus : {{ total_losers }}

    {% if user.profile.is_buro %}

    Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €

    {% endif %}

    Temps de calcul : {{ duration|floatformat }}s

    diff --git a/bda/views.py b/bda/views.py index 0789b9ff..7cec5001 100644 --- a/bda/views.py +++ b/bda/views.py @@ -214,17 +214,17 @@ def do_tirage(request, tirage_id): member.total += show.price members2 = members2.items() data["members2"] = sorted(members2, key=lambda m: m[0].user.last_name) - if False and request.user.username in ["seguin", "harazi","fromherz", "ccadiou"]: - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: - attrib = Attribution(spectacle=show, participant=member) - attrib.save() + # À partir d'ici, le tirage devient effectif + Attribution.objects.all().delete() + for (show, members, _) in results: + for (member, _, _, _) in members: + attrib = Attribution(spectacle=show, participant=member) + attrib.save() return render(request, "bda-attrib-extra.html", data) else: return render(request, "bda-attrib.html", data) -@login_required +@buro_required def tirage(request, tirage_id): if request.POST: form = TokenForm(request.POST) From 299c5f0823cbf410cb60493788874c7954c2b531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 14:17:02 +0200 Subject: [PATCH 15/37] Correction de bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Liens invalide dans le template pour visualisé les places obtenues - Erreurs dans la vue pour visualiser l'état des demandes --- bda/templates/resume_places.html | 2 +- bda/views.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bda/templates/resume_places.html b/bda/templates/resume_places.html index 4d9a8294..8954d7c3 100644 --- a/bda/templates/resume_places.html +++ b/bda/templates/resume_places.html @@ -12,7 +12,7 @@ {% endfor %}

    Total à payer : {{ total|floatformat }}€

    -

    Exporter au format calendrier (.ics, compatible avec tous les logiciels d'agenda)

    +

    Exporter au format calendrier (.ics, compatible avec tous les logiciels d'agenda)

    {% else %}

    Vous n'avez aucune place :(

    {% endif %} diff --git a/bda/views.py b/bda/views.py index 7cec5001..b370dd52 100644 --- a/bda/views.py +++ b/bda/views.py @@ -25,15 +25,15 @@ from bda.forms import BaseBdaFormSet, TokenForm, ResellForm @cof_required def etat_places(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - spectacles1 = ChoixSpectacles.objetcs.filter(tirage=tirage + spectacles1 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage ).filter(double_choice="1" ).all().values('spectacle','spectacle__title' ).annotate(total=models.Count('spectacle')) - spectacles2 = ChoixSpectacles.objetcs.filter(tirage=tirage + spectacles2 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage ).exclude(double_choice="1" ).all().values('spectacle','spectacle__title' ).annotate(total=models.Count('spectacle')) - spectacles = Spectacle.objects.filter(tirage__id=num_tirage).all() + spectacles = Spectacle.objects.filter(tirage=tirage).all() spectacles_dict = {} total = 0 for spectacle in spectacles: From f14a99cb07eaa6bb09d08bcc226c0695f635cd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 16:00:46 +0200 Subject: [PATCH 16/37] Correction dans la vue `do_tirage` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La graine du tirage est sauvegardée et on renomme la variable `tirage` pour lever l'ambiguïté avec la fonction `tirage`. --- bda/views.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bda/views.py b/bda/views.py index b370dd52..51fd2de6 100644 --- a/bda/views.py +++ b/bda/views.py @@ -162,15 +162,17 @@ def inscription(request, tirage_id): "stateerror": stateerror}) def do_tirage(request, tirage_id): - tirage = get_object_or_404(Tirage, id=tirage_id) + tirage_elt = get_object_or_404(Tirage, id=tirage_id) form = TokenForm(request.POST) if not form.is_valid(): return tirage(request) + tirage_elt.token = form.cleaned_data['token'] + tirage_elt.save() start = time.time() data = {} - shows = Spectacle.objects.filter(tirage=tirage).select_related().all() - members = Participant.objects.filter(tirage=tirage).all() - choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage).order_by( + shows = Spectacle.objects.filter(tirage=tirage_elt).select_related().all() + members = Participant.objects.filter(tirage=tirage_elt).all() + choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt).order_by( 'participant', 'priority').select_related().all() algo = Algorithm(shows, members, choices) results = algo(form.cleaned_data["token"]) From 13858b87f3633b9633c6052660433384f2505c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Jun 2016 23:13:22 +0200 Subject: [PATCH 17/37] =?UTF-8?q?=C3=89claircissement=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bda/views.py b/bda/views.py index 51fd2de6..c1b80189 100644 --- a/bda/views.py +++ b/bda/views.py @@ -129,8 +129,10 @@ def inscription(request, tirage_id): { "error_title": "C'est fini !", "error_description": u"Tirage au sort dans la journée !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, - fields=("spectacle","double_choice","priority"), formset=BaseBdaFormSet) + BdaFormSet = inlineformset_factory(Participant, + ChoixSpectacle, + fields=("spectacle","double_choice","priority"), + formset=BaseBdaFormSet) participant, created = Participant.objects.get_or_create( user=request.user, tirage=tirage) success = False From b7d036310d356a3be1d19087a1d4f6ee3b0b4eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 00:11:52 +0200 Subject: [PATCH 18/37] =?UTF-8?q?Mise=20=C3=A0=20jour=20des=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/templates/inscription-bda.html | 2 +- bda/templates/inscription-bda.html.save | 116 ----------------------- bda/templates/inscription-bda2.html | 120 ------------------------ bda/templates/inscription-bda3.html | 120 ------------------------ 4 files changed, 1 insertion(+), 357 deletions(-) delete mode 100644 bda/templates/inscription-bda.html.save delete mode 100644 bda/templates/inscription-bda2.html delete mode 100644 bda/templates/inscription-bda3.html diff --git a/bda/templates/inscription-bda.html b/bda/templates/inscription-bda.html index f760f1b1..5f529eef 100644 --- a/bda/templates/inscription-bda.html +++ b/bda/templates/inscription-bda.html @@ -98,7 +98,7 @@ var django = { {% if stateerror %}

    Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps

    {% endif %} - + {% csrf_token %} {% include "inscription-formset.html" %} diff --git a/bda/templates/inscription-bda.html.save b/bda/templates/inscription-bda.html.save deleted file mode 100644 index c387943f..00000000 --- a/bda/templates/inscription-bda.html.save +++ /dev/null @@ -1,116 +0,0 @@ -{% extends "base_title.html" %} - -{% block extra_head %} - - - - - -{% endblock %} - -{% block realcontent %} - - -

    Inscription au tirage au sort du BDA

    - {% if success %} -

    Votre inscription a été mise à jour avec succès !

    - {% endif %} - - {% csrf_token %} - {% include "inscription-formset.html" %} - - - - Prix total actuel : {{ total_price }}€ -
    -

    - 1: demander deux places pour ce spectacle
    - 2: abandonner une place si impossible d'en obtenir une seconde pour ce spectacle (si vous avez coché l'option Deux places pour ce spectacle)
    - 3: cette liste de vœu est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque vœu
    -

    - -{% endblock %} diff --git a/bda/templates/inscription-bda2.html b/bda/templates/inscription-bda2.html deleted file mode 100644 index 91b08b93..00000000 --- a/bda/templates/inscription-bda2.html +++ /dev/null @@ -1,120 +0,0 @@ -{% extends "base_title.html" %} - -{% block extra_head %} - - - - - -{% endblock %} - -{% block realcontent %} - - -

    Inscription au tirage au sort du BdA

    - {% if success %} -

    Votre inscription a été mise à jour avec succès !

    - {% endif %} - {% if stateerror %} -

    Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps

    - {% endif %} -
    - {% csrf_token %} - {% include "inscription-formset.html" %} - - - - - Prix total actuel : {{ total_price }}€ -
    -

    - 1: demander deux places pour ce spectable
    - 2: abandonner une place si impossible d'en obtenir une seconde pour ce spectacle (si vous avez coché l'option Deux places pour ce spectacle)
    - 3: cette liste de vœu est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque vœu
    -

    - -{% endblock %} diff --git a/bda/templates/inscription-bda3.html b/bda/templates/inscription-bda3.html deleted file mode 100644 index bf77bac8..00000000 --- a/bda/templates/inscription-bda3.html +++ /dev/null @@ -1,120 +0,0 @@ -{% extends "base_title.html" %} - -{% block extra_head %} - - - - - -{% endblock %} - -{% block realcontent %} - - -

    Inscription au tirage au sort du BdA

    - {% if success %} -

    Votre inscription a été mise à jour avec succès !

    - {% endif %} - {% if stateerror %} -

    Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps

    - {% endif %} -
    - {% csrf_token %} - {% include "inscription-formset.html" %} - - - - - Prix total actuel : {{ total_price }}€ -
    -

    - 1: demander deux places pour ce spectable
    - 2: abandonner une place si impossible d'en obtenir une seconde pour ce spectacle (si vous avez coché l'option Deux places pour ce spectacle)
    - 3: cette liste de vœu est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque vœu
    -

    - -{% endblock %} From 7c8f63d75651a1b4f7e5509a85a62e9694f0700f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 00:13:10 +0200 Subject: [PATCH 19/37] Corrections dans les urls --- cof/urls.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cof/urls.py b/cof/urls.py index 6b55e5dd..18e4b5db 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -47,11 +47,13 @@ urlpatterns = patterns('', url(r'^bda/revente/(?P\d+)$', 'bda.views.revente', name = 'bda-revente'), url(r'^bda/etat-places/(?P\d+)$', 'bda.views.etat_places', name = 'bda-etat-places'), url(r'^bda/tirage/(?P\d+)$', 'bda.views.tirage'), - url(r'^bda/spectacles/(?P\d+)/$', lambda tirage_id: ListView(model=Spectacle, - queryset=Spectacle.objects.filter(tirage__id=tirage_id) - ), name ="bda-liste-spectacles"), - url(r'^bda/spectacles/(?P\d+)(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), - url(r'^bda/spectacles/(?P)/liste_spectacles.ics$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), + # FIXME + url(r'^bda/spectacles/(?P\d+)$', lambda request, tirage_id: + ListView(model=Spectacle, + queryset=Spectacle.objects.filter(tirage__id=tirage_id) + ), name ="bda-liste-spectacles"), + url(r'^bda/spectacles/(?P\d+)/(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), + url(r'^bda/spectacles-ics/(?P\d+)$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), url(r'^bda/spectacles/unpaid(?P\d+)$', "bda.views.unpaid", name = "bda-unpaid"), url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), From a4701b9a27154a96229be5bdb75205b1d0c42f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 00:14:08 +0200 Subject: [PATCH 20/37] Correction des urls --- bda/templates/spectacle_list.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bda/templates/spectacle_list.html b/bda/templates/spectacle_list.html index 8c44b14e..a0d2ccbc 100644 --- a/bda/templates/spectacle_list.html +++ b/bda/templates/spectacle_list.html @@ -3,9 +3,9 @@ {% block realcontent %}

    Spectacles

    {% endblock %} From 4b8708d114259422ba4774812c953f4a9b9b3ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 00:14:54 +0200 Subject: [PATCH 21/37] Template utile pour le debug --- gestioncof/templates/utile_bda.html | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/gestioncof/templates/utile_bda.html b/gestioncof/templates/utile_bda.html index d2195fa7..024b2f5f 100644 --- a/gestioncof/templates/utile_bda.html +++ b/gestioncof/templates/utile_bda.html @@ -12,21 +12,9 @@

    Premier tirage

    -

    Deuxième tirage

    - -

    Troisième tirage

    - {% endblock %} From ad145ec70f5ac94e35d2f1db0c6e3a8af2c07dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 11:05:33 +0200 Subject: [PATCH 22/37] Ajout des migrations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Création d'un tirage initial lié à tous les spectacles et participants existants --- bda/migrations/0002_add_tirage.py | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 bda/migrations/0002_add_tirage.py diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py new file mode 100644 index 00000000..15865e5c --- /dev/null +++ b/bda/migrations/0002_add_tirage.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +from django.conf import settings +from django.utils import timezone + +def forwards_func(apps, schema_editor): + Tirage = apps.get_model("bda", "Tirage") + db_alias = schema_editor.connection.alias + Tirage.objects.using(db_alias).bulk_create([ + Tirage( + id=1, + title="Tirage de test (migration)", + active=True, + ouverture=timezone.now(), + fermeture=timezone.now()), + ]) + +def reverse_func(apps, schema_editor): + Tirage = apps.get_model("bda", "Tirage") + db_alias = schema_editor.connection.alias + Tirage.objects.using(db_alias).delete() + +class Migration(migrations.Migration): + + dependencies = [ + ('bda', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Tirage', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=300, verbose_name=b'Titre')), + ('ouverture', models.DateTimeField(verbose_name=b"Date et heure d'ouverture du tirage")), + ('fermeture', models.DateTimeField(verbose_name=b'Date et heure de fermerture du tirage')), + ('token', models.TextField(verbose_name=b'Graine du tirage', blank=True)), + ('active', models.BooleanField(default=True, verbose_name=b'Tirage actif')), + ], + ), + migrations.RunPython(forwards_func, reverse_func), + migrations.AlterField( + model_name='participant', + name='user', + field=models.ForeignKey(to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='participant', + name='tirage', + field=models.ForeignKey(default=1, to='bda.Tirage'), + preserve_default=False, + ), + migrations.AddField( + model_name='spectacle', + name='tirage', + field=models.ForeignKey(default=1, to='bda.Tirage'), + preserve_default=False, + ), + ] From 366daf7240013df79a899a270753b89f224a855b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 11:11:33 +0200 Subject: [PATCH 23/37] Nettoyage du code --- bda/views.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bda/views.py b/bda/views.py index c1b80189..a14380d8 100644 --- a/bda/views.py +++ b/bda/views.py @@ -25,14 +25,18 @@ from bda.forms import BaseBdaFormSet, TokenForm, ResellForm @cof_required def etat_places(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - spectacles1 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage - ).filter(double_choice="1" - ).all().values('spectacle','spectacle__title' - ).annotate(total=models.Count('spectacle')) - spectacles2 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage - ).exclude(double_choice="1" - ).all().values('spectacle','spectacle__title' - ).annotate(total=models.Count('spectacle')) + spectacles1 = ChoixSpectacle.objects \ + .filter(spectacle__tirage=tirage) \ + .filter(double_choice="1") \ + .all() \ + .values('spectacle','spectacle__title') \ + .annotate(total=models.Count('spectacle')) + spectacles2 = ChoixSpectacle.objects \ + .filter(spectacle__tirage=tirage) \ + .exclude(double_choice="1") \ + .all() \ + .values('spectacle','spectacle__title') \ + .annotate(total=models.Count('spectacle')) spectacles = Spectacle.objects.filter(tirage=tirage).all() spectacles_dict = {} total = 0 From 759893f72831e8204f48d98171caa1de77be0be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 11:19:27 +0200 Subject: [PATCH 24/37] Fusion BdA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Les tirages ont un champ `active` pour indiquer si le tirage doit être affiché ou considéré comme archivé. - La page d'accueil n'affiche que les tirages actifs. - Le formulaire d'inscription ne propose plus que les spectacles du tirage concerné. --- bda/models.py | 1 + bda/views.py | 10 ++++++++-- gestioncof/templates/home.html | 18 ++++++++++-------- gestioncof/views.py | 11 +++++++---- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/bda/models.py b/bda/models.py index 9fc66075..2926bb80 100644 --- a/bda/models.py +++ b/bda/models.py @@ -12,6 +12,7 @@ class Tirage(models.Model): ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") fermeture = models.DateTimeField("Date et heure de fermerture du tirage") token = models.TextField("Graine du tirage", blank=True) + active = models.BooleanField("Tirage actif", default=True) def date_no_seconds(self): return self.fermeture.strftime('%d %b %Y %H:%M') diff --git a/bda/views.py b/bda/views.py index a14380d8..9a901cfb 100644 --- a/bda/views.py +++ b/bda/views.py @@ -133,10 +133,16 @@ def inscription(request, tirage_id): { "error_title": "C'est fini !", "error_description": u"Tirage au sort dans la journée !", "choices": choices}) - BdaFormSet = inlineformset_factory(Participant, + def formfield_callback(f, **kwargs): + if f.name == "spectacle": + kwargs['queryset'] = Spectacle.objects.filter(tirage=tirage) + return f.formfield(**kwargs) + BdaFormSet = inlineformset_factory( + Participant, ChoixSpectacle, fields=("spectacle","double_choice","priority"), - formset=BaseBdaFormSet) + formset=BaseBdaFormSet, + formfield_callback=formfield_callback) participant, created = Participant.objects.get_or_create( user=request.user, tirage=tirage) success = False diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index fe713f61..f0aecebc 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -24,17 +24,19 @@ {% if user.profile.is_cof %} -

    BdA

    + {% if open_tirages %} +

    Tirages du BdA

    + {% for tirage in open_tirages %} + {% endfor %} + {% endif %} {% endif %}

    Divers

    diff --git a/gestioncof/views.py b/gestioncof/views.py index 97abfd7c..b90b5842 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -20,14 +20,17 @@ from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \ SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \ RegistrationProfileForm, AdminEventForm, EventForm +from bda.models import Tirage + import re @login_required def home(request): - data = {"surveys": Survey.objects.filter(old = False).all(), - "events": Event.objects.filter(old = False).all(), - "open_surveys": Survey.objects.filter(survey_open = True, old = False).all(), - "open_events": Event.objects.filter(registration_open = True, old = False).all()} + data = {"surveys": Survey.objects.filter(old=False).all(), + "events": Event.objects.filter(old=False).all(), + "open_surveys": Survey.objects.filter(survey_open=True, old=False).all(), + "open_events": Event.objects.filter(registration_open=True, old=False).all(), + "open_tirages": Tirage.objects.filter(active=True).all()} return render(request, "home.html", data) def login(request): From e29184e7d56674bf1fb989e962e0663524ac7700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 13:20:14 +0200 Subject: [PATCH 25/37] =?UTF-8?q?Emp=C3=AAche=20le=20tirage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/views.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bda/views.py b/bda/views.py index 9a901cfb..1e55e076 100644 --- a/bda/views.py +++ b/bda/views.py @@ -229,11 +229,12 @@ def do_tirage(request, tirage_id): members2 = members2.items() data["members2"] = sorted(members2, key=lambda m: m[0].user.last_name) # À partir d'ici, le tirage devient effectif - Attribution.objects.all().delete() - for (show, members, _) in results: - for (member, _, _, _) in members: - attrib = Attribution(spectacle=show, participant=member) - attrib.save() + if False: + Attribution.objects.all().delete() + for (show, members, _) in results: + for (member, _, _, _) in members: + attrib = Attribution(spectacle=show, participant=member) + attrib.save() return render(request, "bda-attrib-extra.html", data) else: return render(request, "bda-attrib.html", data) From 8266afd6acbfcf64e974776f3f3402449625e4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 13:21:16 +0200 Subject: [PATCH 26/37] Ajoute le nom du tirage dans __unicode__ --- bda/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bda/models.py b/bda/models.py index 2926bb80..07e9158d 100644 --- a/bda/models.py +++ b/bda/models.py @@ -18,7 +18,7 @@ class Tirage(models.Model): return self.fermeture.strftime('%d %b %Y %H:%M') def __unicode__(self): - return u"Tirage au sort du BdA du %s" % (self.date_no_seconds()) + return u"%s - %s" % (self.title, self.date_no_seconds()) class Salle (models.Model): name = models.CharField ("Nom", max_length = 300) From 9728384629aa59e2e3a038f867bd2119fff64559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 18:43:56 +0200 Subject: [PATCH 27/37] =?UTF-8?q?R=C3=A9paration=20des=20derni=C3=A8res=20?= =?UTF-8?q?vues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Les liens utiles du BdA affichent tous les tirages en cours. - La listes des spectacles s'affiche --- bda/templates/spectacle_list.html | 4 ++-- bda/views.py | 19 +++++++++++++++++-- cof/urls.py | 12 +++--------- gestioncof/templates/utile_bda.html | 13 ++++++++----- gestioncof/views.py | 3 ++- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/bda/templates/spectacle_list.html b/bda/templates/spectacle_list.html index a0d2ccbc..d707dde4 100644 --- a/bda/templates/spectacle_list.html +++ b/bda/templates/spectacle_list.html @@ -3,9 +3,9 @@ {% block realcontent %}

    Spectacles

    {% endblock %} diff --git a/bda/views.py b/bda/views.py index 1e55e076..4939e2db 100644 --- a/bda/views.py +++ b/bda/views.py @@ -11,6 +11,7 @@ import hashlib from django.core.mail import send_mail from django.utils import timezone +from django.views.generic.list import ListView from datetime import timedelta import time @@ -299,18 +300,32 @@ def spectacle(request, tirage_id, spectacle_id): spectacle = get_object_or_404(Spectacle, id = spectacle_id, tirage=tirage) return render(request, "bda-emails.html", {"spectacle": spectacle}) + +class SpectacleListView(ListView): + model = Spectacle + template_name = 'spectacle_list.html' + def get_queryset(self): + self.tirage = get_object_or_404(Tirage, id=self.kwargs['tirage_id']) + categories = Spectacle.objects.filter(tirage=self.tirage) + return categories + def get_context_data(self, **kwargs): + context = super(SpectacleListView, self).get_context_data(**kwargs) + context['tirage_id'] = self.tirage.id + return context + @buro_required def unpaid(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - unpaid = Participants.objects.filter(tirage=tirage, paid=False).all() + unpaid = Participant.objects.filter(tirage=tirage, paid=False).all() return render(request, "bda-unpaid.html", {"unpaid": unpaid}) @buro_required def liste_spectacles_ics(request, tirage_id): + tirage = get_object_or_404(Tirage, id=tirage_id) spectacles = Spectacle.objects.filter(tirage=tirage).order_by("date").all() for spectacle in spectacles: spectacle.dtend = spectacle.date + timedelta(seconds=7200) return render(request, "liste_spectacles.ics", - { "spectacles": spectacles, "tirage": tirage}, + {"spectacles": spectacles, "tirage": tirage}, content_type="text/calendar") diff --git a/cof/urls.py b/cof/urls.py index 18e4b5db..e841ee02 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -6,9 +6,9 @@ autocomplete_light.autodiscover() from django.contrib import admin admin.autodiscover() -from django.views.generic.list import ListView from django.views.generic.base import TemplateView from bda.models import Spectacle +from bda.views import SpectacleListView from gestioncof.petits_cours_views import DemandeListView urlpatterns = patterns('', @@ -40,22 +40,16 @@ urlpatterns = patterns('', url(r'^petitcours/demandes/(?P\d+)$', 'gestioncof.petits_cours_views.details', name = 'petits-cours-demande-details'), url(r'^petitcours/demandes/(?P\d+)/traitement$', 'gestioncof.petits_cours_views.traitement', name = 'petits-cours-demande-traitement'), url(r'^petitcours/demandes/(?P\d+)/retraitement$', 'gestioncof.petits_cours_views.retraitement', name = 'petits-cours-demande-retraitement'), - url(r'^bda/inscription/(?P\d+)$', 'bda.views.inscription', name = 'bda-tirage-inscription'), url(r'^bda/places/(?P\d+)$', 'bda.views.places', name = "bda-places-attribuees"), url(r'^bda/places/(?P\d+)/places_bda.ics$', 'bda.views.places_ics', name = "bda-places-attribuees-ics"), url(r'^bda/revente/(?P\d+)$', 'bda.views.revente', name = 'bda-revente'), url(r'^bda/etat-places/(?P\d+)$', 'bda.views.etat_places', name = 'bda-etat-places'), url(r'^bda/tirage/(?P\d+)$', 'bda.views.tirage'), - # FIXME - url(r'^bda/spectacles/(?P\d+)$', lambda request, tirage_id: - ListView(model=Spectacle, - queryset=Spectacle.objects.filter(tirage__id=tirage_id) - ), name ="bda-liste-spectacles"), + url(r'^bda/spectacles/(?P\d+)$', SpectacleListView.as_view() , name ="bda-liste-spectacles"), url(r'^bda/spectacles/(?P\d+)/(?P\d+)$', "bda.views.spectacle", name = "bda-spectacle"), url(r'^bda/spectacles-ics/(?P\d+)$', 'bda.views.liste_spectacles_ics', name ="bda-liste-spectacles-ics"), - url(r'^bda/spectacles/unpaid(?P\d+)$', "bda.views.unpaid", name = "bda-unpaid"), - + url(r'^bda/spectacles/unpaid/(?P\d+)$', "bda.views.unpaid", name = "bda-unpaid"), url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), url(r'^event/(?P\d+)$', 'gestioncof.views.event'), url(r'^survey/(?P\d+)/status$', 'gestioncof.views.survey_status'), diff --git a/gestioncof/templates/utile_bda.html b/gestioncof/templates/utile_bda.html index 024b2f5f..5f4f383a 100644 --- a/gestioncof/templates/utile_bda.html +++ b/gestioncof/templates/utile_bda.html @@ -10,11 +10,14 @@
  • BdA diffusion
  • BdA revente
  • -

    Premier tirage

    +

    Tirages

    + {% for tirage in tirages %} +

    {{ tirage.title }}

    + {% endfor %} {% endblock %} diff --git a/gestioncof/views.py b/gestioncof/views.py index b90b5842..def84beb 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -504,7 +504,8 @@ def utile_cof(request): @buro_required def utile_bda(request): - return render(request, "utile_bda.html", {}) + tirages = Tirage.objects.all() + return render(request, "utile_bda.html", {'tirages': tirages}) @buro_required def liste_bdadiff(request): From 2a1c870caced65ba5de587dcb40f65db00327f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 19:22:01 +0200 Subject: [PATCH 28/37] =?UTF-8?q?Emp=C3=AAche=20l'inscription=20=C3=A0=20u?= =?UTF-8?q?n=20tirage=20non=20ouvert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bda/views.py b/bda/views.py index 4939e2db..bf9e438b 100644 --- a/bda/views.py +++ b/bda/views.py @@ -126,6 +126,12 @@ def places_ics(request, tirage_id): @cof_required def inscription(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) + if timezone.now() < tirage.ouverture: + error_desc = "Ouverture le %s" % ( + tirage.ouverture.strftime('%d %b %Y à %H:%M')) + return render(request, 'resume_inscription.html', + { "error_title": "Le tirage n'est pas encore ouvert !", + "error_description": error_desc }) if timezone.now() > tirage.fermeture: participant, created = Participant.objects.get_or_create( user=request.user, tirage=tirage) From 34e23c898a0a95bba7e56f105e8554f6dc3976d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Mon, 6 Jun 2016 23:46:36 +0200 Subject: [PATCH 29/37] Suppression de code mort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La fonction `send_choices` n'est pas branchée et donc pas utilisée. De plus elle est inutile, les vœux des participants étant accessibles en ligne. --- bda/admin.py | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index e1788c6b..338779eb 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -37,42 +37,6 @@ class ParticipantAdmin(admin.ModelAdmin): actions_on_bottom = True list_per_page = 400 - def send_choices(self, request, queryset): - for member in queryset.all(): - choices = member.choixspectacle_set.order_by('priority').all() - if len(choices) == 0: - continue - mail = u"""Cher(e) %s, -Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""" % member.user.get_full_name() - next_rank = 1 - member_shows = {} - for choice in choices: - if choice.spectacle in member_shows: continue - else: member_shows[choice.spectacle] = True - extra = "" - if choice.double: - extra += u" ; deux places" - if choice.autoquit: - extra += u" ; désistement automatique" - mail += u"- Choix %d : %s%s\n" % (next_rank, choice.spectacle, extra) - next_rank += 1 - mail += u"""\nSi cette liste est incorrecte, merci de nous contacter au plus vite (avant samedi 6 octobre 18h). - -Artistiquement, -Le BdA""" - send_mail ("Choix de spectacles (BdA du COF)", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) - count = len(queryset.all()) - if count == 1: - message_bit = u"1 membre a" - plural = "" - else: - message_bit = u"%d membres ont" % count - plural = "s" - self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural)) - send_choices.short_description = u"Envoyer les choix par mail" - def send_attribs(self, request, queryset): for member in queryset.all(): attribs = member.attributions.all() From 178c1a118f8d4babb161194eb0d5a9edd29ba49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 00:00:56 +0200 Subject: [PATCH 30/37] =?UTF-8?q?Mise=20=C3=A0=20jour=20des=20mails=20auto?= =?UTF-8?q?matiques=20des=20tirages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - La deadline pour le paiement est J+7 après la fermeture du tirage. - Les participants n'ayant pas obtenu de place reçoivent un mail les en informant quand les les applications `bda2` et `bda3` supprimée précédement --- bda/admin.py | 52 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/bda/admin.py b/bda/admin.py index 338779eb..8af71d00 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -7,6 +7,8 @@ from django.contrib import admin from django.db.models import Sum, Count from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution, Tirage +from datetime import timedelta + class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle sortable_field_name = "priority" @@ -41,22 +43,34 @@ class ParticipantAdmin(admin.ModelAdmin): for member in queryset.all(): attribs = member.attributions.all() if len(attribs) == 0: - continue - mail = u"""Cher(e) %s, + mail = u"""Cher-e %s, -Tu t'es inscrit(e) pour le tirage au sort du BdA. Tu as été sélectionné(e) +Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as +obtenu aucune place. + +Nous proposons cependant de nombreuses offres hors-tirage tout au long de +l'année, et nous t'invitons à nous contacter si l'une d'entre elles t'intéresse ! +-- +Le Bureau des Arts + +""" + name = member.user.get_full_name() + mail = mail % name + else: + mail = u"""Cher-e %s, + +Tu t'es inscrit-e pour le tirage au sort du BdA. Tu as été sélectionné-e pour les spectacles suivants : %s *Paiement* -L'intégralité de ces places de spectacles est à régler à partir du lundi -6 octobre et AVANT le vendredi 10 octobre, au bureau du COF pendant les -heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h -et 20h). Des facilités de paiement sont bien évidemment possibles : nous -pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre -paiement en deux fois. Pour ceux qui ne pourraient pas venir payer au bureau, -merci de nous contacter par mail. +L'intégralité de ces places de spectacles est à régler dès maintenant et AVANT +le %s, au bureau du COF pendant les heures de permanences (du lundi au vendredi +entre 12h et 14h, et entre 18h et 20h). Des facilités de paiement sont bien +évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement, ou +bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas venir +payer au bureau, merci de nous contacter par mail. *Mode de retrait des places* Au moment du paiement, certaines places vous seront remises directement, d'autres @@ -73,16 +87,16 @@ prochainement disponible, directement sur votre compte GestioCOF. En vous souhaitant de très beaux spectacles tout au long de l'année, -- Le Bureau des Arts -(Jean, Antoine, Élodie, Marion et Louise) """ - attribs_text = "" - name = member.user.get_full_name() - for attrib in attribs: - attribs_text += u"- 1 place pour %s\n" % attrib - mail = mail % (name, attribs_text) - send_mail ("Résultats du tirage au sort", mail, - "bda@ens.fr", [member.user.email], - fail_silently = True) + attribs_text = "" + name = member.user.get_full_name() + for attrib in attribs: + attribs_text += u"- 1 place pour %s\n" % attrib + deadline = member.tirage.fermeture + timedelta(days=7) + mail = mail % (name, attribs_text, deadline.strftime('%d %b %Y')) + send_mail ("Résultats du tirage au sort", mail, + "bda@ens.fr", [member.user.email], + fail_silently = True) count = len(queryset.all()) if count == 1: message_bit = u"1 membre a" From 72739cf5aa1e1c5cba50b001fe90c059998e2f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 00:14:12 +0200 Subject: [PATCH 31/37] Remove useless function --- bda/migrations/0002_add_tirage.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py index 15865e5c..73d597ba 100644 --- a/bda/migrations/0002_add_tirage.py +++ b/bda/migrations/0002_add_tirage.py @@ -17,11 +17,6 @@ def forwards_func(apps, schema_editor): fermeture=timezone.now()), ]) -def reverse_func(apps, schema_editor): - Tirage = apps.get_model("bda", "Tirage") - db_alias = schema_editor.connection.alias - Tirage.objects.using(db_alias).delete() - class Migration(migrations.Migration): dependencies = [ @@ -40,7 +35,7 @@ class Migration(migrations.Migration): ('active', models.BooleanField(default=True, verbose_name=b'Tirage actif')), ], ), - migrations.RunPython(forwards_func, reverse_func), + migrations.RunPython(forwards_func, migrations.RunPython.noop), migrations.AlterField( model_name='participant', name='user', From a683b189f0cab960dc67999bfe3c13969a003c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 00:18:16 +0200 Subject: [PATCH 32/37] Commentaire et FIXME sur le tirage --- bda/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bda/views.py b/bda/views.py index bf9e438b..7d97ca0f 100644 --- a/bda/views.py +++ b/bda/views.py @@ -236,6 +236,8 @@ def do_tirage(request, tirage_id): members2 = members2.items() data["members2"] = sorted(members2, key=lambda m: m[0].user.last_name) # À partir d'ici, le tirage devient effectif + # FIXME: Établir les conditions de validations (formulaire ?) + # cf. issue #32 if False: Attribution.objects.all().delete() for (show, members, _) in results: From 68e3c3412a86830bf704f9cc13f41fd2fd0161a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 22:34:23 +0200 Subject: [PATCH 33/37] =?UTF-8?q?Ne=20permet=20pas=20de=20d=C3=A9finir=20u?= =?UTF-8?q?n=20spectacle=20sans=20prix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bda/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bda/models.py b/bda/models.py index 07e9158d..89ca74ab 100644 --- a/bda/models.py +++ b/bda/models.py @@ -33,7 +33,7 @@ class Spectacle (models.Model): location = models.ForeignKey(Salle) description = models.TextField ("Description", blank=True) slots_description = models.TextField ("Description des places", blank=True) - price = models.FloatField("Prix d'une place", blank=True) + price = models.FloatField("Prix d'une place") slots = models.IntegerField ("Places") priority = models.IntegerField ("Priorité", default=1000) tirage = models.ForeignKey (Tirage) From 688dce33d58b5232c9c7c68323006744d4bff299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 22:36:43 +0200 Subject: [PATCH 34/37] =?UTF-8?q?Espaces=20en=20trop=20avant=20les=20paren?= =?UTF-8?q?th=C3=A8ses.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supprimés --- bda/models.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/bda/models.py b/bda/models.py index 89ca74ab..251e0e3e 100644 --- a/bda/models.py +++ b/bda/models.py @@ -20,23 +20,23 @@ class Tirage(models.Model): def __unicode__(self): return u"%s - %s" % (self.title, self.date_no_seconds()) -class Salle (models.Model): - name = models.CharField ("Nom", max_length = 300) - address = models.TextField ("Adresse") +class Salle(models.Model): + name = models.CharField("Nom", max_length = 300) + address = models.TextField("Adresse") def __unicode__ (self): return self.name -class Spectacle (models.Model): - title = models.CharField ("Titre", max_length=300) - date = models.DateTimeField ("Date & heure") +class Spectacle(models.Model): + title = models.CharField("Titre", max_length=300) + date = models.DateTimeField("Date & heure") location = models.ForeignKey(Salle) - description = models.TextField ("Description", blank=True) - slots_description = models.TextField ("Description des places", blank=True) + description = models.TextField("Description", blank=True) + slots_description = models.TextField("Description des places", blank=True) price = models.FloatField("Prix d'une place") - slots = models.IntegerField ("Places") - priority = models.IntegerField ("Priorité", default=1000) - tirage = models.ForeignKey (Tirage) + slots = models.IntegerField("Places") + priority = models.IntegerField("Priorité", default=1000) + tirage = models.ForeignKey(Tirage) class Meta: verbose_name = "Spectacle" @@ -62,7 +62,7 @@ PAYMENT_TYPES = ( ("autre",u"Autre"), ) -class Participant (models.Model): +class Participant(models.Model): user = models.ForeignKey(User) choices = models.ManyToManyField(Spectacle, through="ChoixSpectacle", @@ -84,7 +84,7 @@ DOUBLE_CHOICES = ( ("double", "2 places sinon rien"), ) -class ChoixSpectacle (models.Model): +class ChoixSpectacle(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="participants") priority = models.PositiveIntegerField("Priorité") @@ -105,7 +105,7 @@ class ChoixSpectacle (models.Model): verbose_name = "voeu" verbose_name_plural = "voeux" -class Attribution (models.Model): +class Attribution(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="attribues") given = models.BooleanField(u"Donnée", default=False) From ccd38d2723fb63184df979af6d66306a54d8e0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 22:49:19 +0200 Subject: [PATCH 35/37] Remplace `filter` par `_set` quand c'est possible Par exemple `Spectacle.objects.filter(tirage=tirage)` devient `tirage.spectacle_set` --- bda/views.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bda/views.py b/bda/views.py index 7d97ca0f..624f0a3b 100644 --- a/bda/views.py +++ b/bda/views.py @@ -38,7 +38,7 @@ def etat_places(request, tirage_id): .all() \ .values('spectacle','spectacle__title') \ .annotate(total=models.Count('spectacle')) - spectacles = Spectacle.objects.filter(tirage=tirage).all() + spectacles = tirage.spectacle_set.all() spectacles_dict = {} total = 0 for spectacle in spectacles: @@ -142,7 +142,7 @@ def inscription(request, tirage_id): "choices": choices}) def formfield_callback(f, **kwargs): if f.name == "spectacle": - kwargs['queryset'] = Spectacle.objects.filter(tirage=tirage) + kwargs['queryset'] = tirage.spectacle_set return f.formfield(**kwargs) BdaFormSet = inlineformset_factory( Participant, @@ -189,8 +189,8 @@ def do_tirage(request, tirage_id): tirage_elt.save() start = time.time() data = {} - shows = Spectacle.objects.filter(tirage=tirage_elt).select_related().all() - members = Participant.objects.filter(tirage=tirage_elt).all() + shows = tirage_elt.spectacle_set.select_related().all() + members = tirage_elt.spectacle_set.all() choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt).order_by( 'participant', 'priority').select_related().all() algo = Algorithm(shows, members, choices) @@ -324,13 +324,13 @@ class SpectacleListView(ListView): @buro_required def unpaid(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - unpaid = Participant.objects.filter(tirage=tirage, paid=False).all() + unpaid = tirage.participant_set.filter(paid=False).all() return render(request, "bda-unpaid.html", {"unpaid": unpaid}) @buro_required def liste_spectacles_ics(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) - spectacles = Spectacle.objects.filter(tirage=tirage).order_by("date").all() + spectacles = tirage.spectacle_set.order_by("date").all() for spectacle in spectacles: spectacle.dtend = spectacle.date + timedelta(seconds=7200) return render(request, "liste_spectacles.ics", From 27bf9c5231082b15bdf99a59d82d8fd0e24c6e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 22:54:11 +0200 Subject: [PATCH 36/37] Petit oubli cf. ccd38d2723fb63184df979af6d66306a54d8e0a0 --- bda/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bda/views.py b/bda/views.py index 624f0a3b..ed653b54 100644 --- a/bda/views.py +++ b/bda/views.py @@ -314,7 +314,7 @@ class SpectacleListView(ListView): template_name = 'spectacle_list.html' def get_queryset(self): self.tirage = get_object_or_404(Tirage, id=self.kwargs['tirage_id']) - categories = Spectacle.objects.filter(tirage=self.tirage) + categories = self.tirage.spectacle_set return categories def get_context_data(self, **kwargs): context = super(SpectacleListView, self).get_context_data(**kwargs) From 4933cc61b2ba77f6c8a8055507a8290d1dabf7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 7 Jun 2016 23:07:28 +0200 Subject: [PATCH 37/37] =?UTF-8?q?Tirage=20inactif=20par=20d=C3=A9faut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dans les modèles et dans le tirage de test de la migration --- bda/migrations/0002_add_tirage.py | 2 +- bda/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bda/migrations/0002_add_tirage.py b/bda/migrations/0002_add_tirage.py index 73d597ba..1956a4a4 100644 --- a/bda/migrations/0002_add_tirage.py +++ b/bda/migrations/0002_add_tirage.py @@ -12,7 +12,7 @@ def forwards_func(apps, schema_editor): Tirage( id=1, title="Tirage de test (migration)", - active=True, + active=False, ouverture=timezone.now(), fermeture=timezone.now()), ]) diff --git a/bda/models.py b/bda/models.py index 251e0e3e..cab8ce41 100644 --- a/bda/models.py +++ b/bda/models.py @@ -12,7 +12,7 @@ class Tirage(models.Model): ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") fermeture = models.DateTimeField("Date et heure de fermerture du tirage") token = models.TextField("Graine du tirage", blank=True) - active = models.BooleanField("Tirage actif", default=True) + active = models.BooleanField("Tirage actif", default=False) def date_no_seconds(self): return self.fermeture.strftime('%d %b %Y %H:%M')