diff --git a/apache/wsgi.py b/apache/wsgi.py index 254e36f5..b7a1eb92 100644 --- a/apache/wsgi.py +++ b/apache/wsgi.py @@ -6,7 +6,7 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ """ import os -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings") - from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings") application = get_wsgi_application() diff --git a/bda/admin.py b/bda/admin.py index a86a9766..bcbc6069 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -4,27 +4,36 @@ from django.core.mail import send_mail from django.contrib import admin from django.db.models import Sum, Count -from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution, Tirage +from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ + Attribution, Tirage from django import forms from datetime import timedelta +import autocomplete_light + + class ChoixSpectacleInline(admin.TabularInline): model = ChoixSpectacle sortable_field_name = "priority" + class AttributionInline(admin.TabularInline): model = Attribution + class ParticipantAdmin(admin.ModelAdmin): 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: @@ -51,8 +60,9 @@ class ParticipantAdmin(admin.ModelAdmin): 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 ! +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 @@ -71,15 +81,16 @@ pour les spectacles suivants : 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. +évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement, +ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas +venir payer au bureau, merci de nous contacter par mail. *Mode de retrait des places* -Au moment du paiement, certaines places vous seront remises directement, d'autres -seront à récupérer au cours de l'année, d'autres encore seront nominatives et à retirer -le soir même dans les theâtres correspondants. Pour chaque spectacle, vous recevrez un mail -quelques jours avant la représentation vous indiquant le mode de retrait. +Au moment du paiement, certaines places vous seront remises directement, +d'autres seront à récupérer au cours de l'année, d'autres encore seront +nominatives et à retirer le soir même dans les theâtres correspondants. +Pour chaque spectacle, vous recevrez un mail quelques jours avant la +représentation vous indiquant le mode de retrait. Nous vous rappelons que l'obtention de places du BdA vous engage à respecter les règles de fonctionnement : @@ -96,10 +107,11 @@ Le Bureau des Arts 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) + 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" @@ -107,9 +119,11 @@ Le Bureau des Arts 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)) + 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 AttributionAdminForm(forms.ModelForm): def clean(self): cleaned_data = super(AttributionAdminForm, self).clean() @@ -117,26 +131,36 @@ class AttributionAdminForm(forms.ModelForm): spectacle = cleaned_data.get("spectacle") if participant and spectacle: if participant.tirage != spectacle.tirage: - raise forms.ValidationError(u"Erreur : le participant et le spectacle n'appartiennent pas au même tirage") + raise forms.ValidationError( + u"Erreur : le participant et le spectacle n'appartiennent" + u"pas au même tirage") return cleaned_data + 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') + search_fields = ('spectacle__title', 'participant__user__username', + 'participant__user__first_name', + 'participant__user__last_name') form = AttributionAdminForm -import autocomplete_light + class ChoixSpectacleAdmin(admin.ModelAdmin): form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) + def tirage(self, obj): return obj.participant.tirage - list_display = ("participant", "tirage", "spectacle", "priority", "double_choice") + list_display = ("participant", "tirage", "spectacle", "priority", + "double_choice") list_filter = ("double_choice", "participant__tirage") - search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') + search_fields = ('participant__user__username', + 'participant__user__first_name', + 'participant__user__last_name') + class SpectacleAdmin(admin.ModelAdmin): model = Spectacle @@ -144,6 +168,7 @@ class SpectacleAdmin(admin.ModelAdmin): list_filter = ("location", "tirage",) search_fields = ("title", "location__name") + class TirageAdmin(admin.ModelAdmin): model = Tirage list_display = ("title", "ouverture", "fermeture", "active") diff --git a/bda/algorithm.py b/bda/algorithm.py index 21825369..a948d288 100644 --- a/bda/algorithm.py +++ b/bda/algorithm.py @@ -6,6 +6,7 @@ from django.db.models import Max import random + class Algorithm(object): shows = None @@ -19,7 +20,8 @@ class Algorithm(object): 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.max_group = \ + 2 * choices.aggregate(Max('priority'))['priority__max'] self.shows = [] showdict = {} for show in shows: @@ -65,13 +67,14 @@ class Algorithm(object): def __call__(self, seed): random.seed(seed) results = [] - shows = sorted(self.shows, key=lambda x: x.nrequests / x.slots, reverse=True) + shows = sorted(self.shows, key=lambda x: 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) + raise RuntimeError(member, show.title) groups[self.ranks[member][show]].append(member) # On passe à l'attribution winners = [] @@ -84,7 +87,8 @@ class Algorithm(object): 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: + elif not self.choices[member][show].autoquit and\ + len(winners) < show.slots: self.appendResult(winners, member, show) self.appendResult(losers, member, show) else: diff --git a/bda/autocomplete_light_registry.py b/bda/autocomplete_light_registry.py index 3254b3c8..7aa43b07 100644 --- a/bda/autocomplete_light_registry.py +++ b/bda/autocomplete_light_registry.py @@ -2,8 +2,11 @@ import autocomplete_light from bda.models import Participant, Spectacle -autocomplete_light.register(Participant, search_fields=('user__username','user__first_name','user__last_name'), +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_light.register( + Spectacle, search_fields=('title', ), autocomplete_js_attributes={'placeholder': 'spectacle...'}) diff --git a/bda/forms.py b/bda/forms.py index cfc48266..1b93c6ef 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -4,6 +4,7 @@ from django import forms from django.forms.models import BaseInlineFormSet from bda.models import Spectacle + class BaseBdaFormSet(BaseInlineFormSet): def clean(self): """Checks that no two articles have the same title.""" @@ -20,22 +21,27 @@ 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()) + 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() + self.fields['spectacle'].queryset = participant.attributions.all().\ + distinct() diff --git a/bda/models.py b/bda/models.py index 1f160bbe..fbb6e0ee 100644 --- a/bda/models.py +++ b/bda/models.py @@ -6,6 +6,7 @@ from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ + class Tirage(models.Model): title = models.CharField("Titre", max_length=300) ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") @@ -19,6 +20,7 @@ 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") @@ -26,6 +28,7 @@ class Salle(models.Model): def __unicode__(self): return self.name + class Spectacle(models.Model): title = models.CharField("Titre", max_length=300) date = models.DateTimeField("Date & heure") @@ -52,7 +55,7 @@ class Spectacle(models.Model): def __unicode__(self): return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), - self.location, self.price) + self.location, self.price) PAYMENT_TYPES = ( ("cash", u"Cash"), @@ -61,17 +64,19 @@ PAYMENT_TYPES = ( ("autre", u"Autre"), ) + class Participant(models.Model): user = models.ForeignKey(User) choices = models.ManyToManyField(Spectacle, - through="ChoixSpectacle", - related_name="chosen_by") + through="ChoixSpectacle", + related_name="chosen_by") attributions = models.ManyToManyField(Spectacle, - through="Attribution", - related_name="attributed_to") + 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) + max_length=6, choices=PAYMENT_TYPES, + blank=True) tirage = models.ForeignKey(Tirage) def __unicode__(self): @@ -83,12 +88,14 @@ DOUBLE_CHOICES = ( ("double", "2 places sinon rien"), ) + class ChoixSpectacle(models.Model): participant = models.ForeignKey(Participant) 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) + default="1", choices=DOUBLE_CHOICES, + max_length=10) def get_double(self): return self.double_choice != "1" @@ -104,6 +111,7 @@ class ChoixSpectacle(models.Model): verbose_name = "voeu" verbose_name_plural = "voeux" + class Attribution(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="attribues") diff --git a/bda/urls.py b/bda/urls.py index f8e385b8..4557ec86 100644 --- a/bda/urls.py +++ b/bda/urls.py @@ -3,7 +3,8 @@ from django.conf.urls import url, patterns from bda.views import SpectacleListView -urlpatterns = patterns('', +urlpatterns = patterns( + '', url(r'inscription/(?P\d+)$', 'bda.views.inscription', name='bda-tirage-inscription'), diff --git a/bda/views.py b/bda/views.py index 3167ec16..c09b5baa 100644 --- a/bda/views.py +++ b/bda/views.py @@ -18,7 +18,8 @@ from datetime import timedelta import time from gestioncof.decorators import cof_required, buro_required -from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution, Tirage +from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\ + Tirage from bda.algorithm import Algorithm from bda.forms import BaseBdaFormSet, TokenForm, ResellForm @@ -59,7 +60,7 @@ def etat_places(request, tirage_id): spectacles_dict[spectacle["spectacle"]].slots total += spectacle["total"] return render(request, "etat-places.html", - {"spectacles": spectacles, "total": total, 'tirage': tirage}) + {"spectacles": spectacles, "total": total, 'tirage': tirage}) def _hash_queryset(queryset): @@ -73,9 +74,9 @@ def _hash_queryset(queryset): 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) + user=request.user, tirage=tirage) places = participant.attribution_set.order_by( - "spectacle__date", "spectacle").all() + "spectacle__date", "spectacle").all() total = sum([place.spectacle.price for place in places]) filtered_places = [] places_dict = {} @@ -107,9 +108,9 @@ def places(request, tirage_id): 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) + user=request.user, tirage=tirage) places = participant.attribution_set.order_by( - "spectacle__date", "spectacle").all() + "spectacle__date", "spectacle").all() filtered_places = [] places_dict = {} spectacles = [] @@ -133,30 +134,32 @@ 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')) + 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}) + {"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) + 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}) + {"error_title": "C'est fini !", + "error_description": + u"Tirage au sort dans la journée !", + "choices": choices}) + def formfield_callback(f, **kwargs): if f.name == "spectacle": kwargs['queryset'] = tirage.spectacle_set return f.formfield(**kwargs) BdaFormSet = inlineformset_factory( - Participant, - ChoixSpectacle, - fields=("spectacle", "double_choice", "priority"), - formset=BaseBdaFormSet, - formfield_callback=formfield_callback) + Participant, + ChoixSpectacle, + fields=("spectacle", "double_choice", "priority"), + formset=BaseBdaFormSet, + formfield_callback=formfield_callback) participant, created = Participant.objects.get_or_create( - user=request.user, tirage=tirage) + user=request.user, tirage=tirage) success = False stateerror = False if request.method == "POST": @@ -179,12 +182,12 @@ def inscription(request, tirage_id): if choice.double: total_price += choice.spectacle.price return render(request, "inscription-bda.html", - { "formset": formset, - "success": success, - "total_price": total_price, - "dbstate": dbstate, - 'tirage': tirage, - "stateerror": stateerror}) + {"formset": formset, + "success": success, + "total_price": total_price, + "dbstate": dbstate, + 'tirage': tirage, + "stateerror": stateerror}) def do_tirage(request, tirage_id): @@ -198,8 +201,8 @@ def do_tirage(request, tirage_id): data = {} shows = tirage_elt.spectacle_set.select_related().all() members = tirage_elt.participant_set.all() - choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt).order_by( - 'participant', 'priority').select_related().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"]) total_slots = 0 @@ -248,8 +251,8 @@ def do_tirage(request, tirage_id): # cf. issue #32 if False: Attribution.objects.filter( - spectacle__tirage=tirage_elt - ).delete() + spectacle__tirage=tirage_elt + ).delete() for (show, members, _) in results: for (member, _, _, _) in members: attrib = Attribution(spectacle=show, participant=member) @@ -280,19 +283,20 @@ 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) + 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}) + return render(request, "bda-success.html", + {"show": spectacle, "places": places}) @login_required 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) + user=request.user, tirage=tirage) if not participant.paid: return render(request, "bda-notpaid.html", {}) if request.POST: @@ -301,7 +305,8 @@ def revente(request, tirage_id): return do_resell(request, form) else: form = ResellForm(participant) - return render(request, "bda-revente.html", {"form": form, 'tirage': tirage}) + return render(request, "bda-revente.html", + {"form": form, 'tirage': tirage}) @buro_required @@ -326,9 +331,9 @@ def spectacle(request, tirage_id, spectacle_id): participants[participant.id] = participant_info participants_info = sorted(participants.values(), - key=lambda part: part['lastname']) + key=lambda part: part['lastname']) return render(request, "bda-participants.html", - {"spectacle": spectacle, "participants": participants_info}) + {"spectacle": spectacle, "participants": participants_info}) class SpectacleListView(ListView): @@ -351,8 +356,8 @@ class SpectacleListView(ListView): def unpaid(request, tirage_id): tirage = get_object_or_404(Tirage, id=tirage_id) unpaid = tirage.participant_set \ - .annotate(nb_attributions=Count('attribution')) \ - .filter(paid=False, nb_attributions__gt=0).all() + .annotate(nb_attributions=Count('attribution')) \ + .filter(paid=False, nb_attributions__gt=0).all() return render(request, "bda-unpaid.html", {"unpaid": unpaid}) @@ -363,5 +368,5 @@ def liste_spectacles_ics(request, tirage_id): for spectacle in spectacles: spectacle.dtend = spectacle.date + timedelta(seconds=7200) return render(request, "liste_spectacles.ics", - {"spectacles": spectacles, "tirage": tirage}, - content_type="text/calendar") + {"spectacles": spectacles, "tirage": tirage}, + content_type="text/calendar") diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 75f67646..6f2f21ac 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -148,11 +148,14 @@ RECAPTCHA_PUBLIC_KEY = "DUMMY" RECAPTCHA_PRIVATE_KEY = "DUMMY" RECAPTCHA_USE_SSL = True -# On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar car -# cela interfère avec l'utilisation de Vagrant. En effet, l'adresse de la -# machine physique n'est pas forcément connue, et peut difficilement être mise -# dans les INTERNAL_IPS. + def show_toolbar(request): + """ + On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar + car cela interfère avec l'utilisation de Vagrant. En effet, l'adresse de la + machine physique n'est pas forcément connue, et peut difficilement être + mise dans les INTERNAL_IPS. + """ if not DEBUG: return False if request.is_ajax(): diff --git a/cof/urls.py b/cof/urls.py index 817db2dc..e42af37c 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -12,7 +12,8 @@ from gestioncof.urls import export_patterns, petitcours_patterns, \ autocomplete_light.autodiscover() admin.autodiscover() -urlpatterns = patterns('', +urlpatterns = patterns( + '', # Page d'accueil url(r'^$', 'gestioncof.views.home', name='home'), # Le BdA @@ -27,38 +28,39 @@ urlpatterns = patterns('', url(r'^event/', include(events_patterns)), # Authentification url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'), - name="cof-denied"), + name="cof-denied"), url(r'^cas/login$', 'django_cas_ng.views.login', name="cas_login_view"), url(r'^cas/logout$', 'django_cas_ng.views.logout'), url(r'^outsider/login$', 'gestioncof.views.login_ext'), url(r'^outsider/logout$', 'django.contrib.auth.views.logout', - {'next_page': 'home'}), + {'next_page': 'home'}), url(r'^login$', 'gestioncof.views.login'), url(r'^logout$', 'gestioncof.views.logout'), # Infos persos url(r'^profile$', 'gestioncof.views.profile'), url(r'^outsider/password-change$', - 'django.contrib.auth.views.password_change'), + 'django.contrib.auth.views.password_change'), url(r'^outsider/password-change-done$', 'django.contrib.auth.views.password_change_done', name='password_change_done'), # Inscription d'un nouveau membre url(r'^registration$', 'gestioncof.views.registration'), url(r'^registration/clipper/(?P[\w-]+)$', - 'gestioncof.views.registration_form2', name="clipper-registration"), + 'gestioncof.views.registration_form2', name="clipper-registration"), url(r'^registration/user/(?P.+)$', - 'gestioncof.views.registration_form2', name="user-registration"), + 'gestioncof.views.registration_form2', name="user-registration"), url(r'^registration/empty$', 'gestioncof.views.registration_form2', - name="empty-registration"), + name="empty-registration"), # Autocompletion - url(r'^autocomplete/registration$', 'gestioncof.autocomplete.autocomplete'), + url(r'^autocomplete/registration$', + 'gestioncof.autocomplete.autocomplete'), url(r'^autocomplete/', include('autocomplete_light.urls')), # Interface admin url(r'^admin/logout/', 'gestioncof.views.logout'), url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/', - 'gestioncof.csv_views.admin_list_export', - {'fields': ['username', ]}), + 'gestioncof.csv_views.admin_list_export', + {'fields': ['username', ]}), url(r'^admin/', include(admin.site.urls)), url(r'^grappelli/', include('grappelli.urls')), # Liens utiles du COF et du BdA diff --git a/gestioncof/admin.py b/gestioncof/admin.py index 2c149ed0..3d5e8891 100644 --- a/gestioncof/admin.py +++ b/gestioncof/admin.py @@ -9,8 +9,11 @@ from django.core.urlresolvers import reverse from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +import autocomplete_light -def add_link_field(target_model='', field='', link_text=unicode, desc_text=unicode): + +def add_link_field(target_model='', field='', link_text=unicode, + desc_text=unicode): def add_link(cls): reverse_name = target_model or cls.model.__name__.lower() @@ -21,11 +24,13 @@ def add_link_field(target_model='', field='', link_text=unicode, desc_text=unico if not link_obj.id: return "" url = reverse(reverse_path, args=(link_obj.id,)) - return mark_safe("%s" % (url, link_text(link_obj))) + return mark_safe("%s" % + (url, link_text(link_obj))) link.allow_tags = True link.short_description = desc_text(reverse_name + ' link') cls.link = link - cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + ['link'] + cls.readonly_fields =\ + list(getattr(cls, 'readonly_fields', [])) + ['link'] return cls return add_link @@ -42,14 +47,14 @@ class SurveyQuestionInline(admin.TabularInline): class SurveyQuestionAdmin(admin.ModelAdmin): inlines = [ - SurveyQuestionAnswerInline, - ] + SurveyQuestionAnswerInline, + ] class SurveyAdmin(admin.ModelAdmin): inlines = [ - SurveyQuestionInline, - ] + SurveyQuestionInline, + ] class EventOptionChoiceInline(admin.TabularInline): @@ -68,15 +73,15 @@ class EventCommentFieldInline(admin.TabularInline): class EventOptionAdmin(admin.ModelAdmin): inlines = [ - EventOptionChoiceInline, - ] + EventOptionChoiceInline, + ] class EventAdmin(admin.ModelAdmin): inlines = [ - EventOptionInline, - EventCommentFieldInline, - ] + EventOptionInline, + EventCommentFieldInline, + ] class CofProfileInline(admin.StackedInline): @@ -85,7 +90,8 @@ class CofProfileInline(admin.StackedInline): class FkeyLookup(object): - def __init__(self, fkeydecl, short_description=None, admin_order_field=None): + def __init__(self, fkeydecl, short_description=None, + admin_order_field=None): self.fk, fkattrs = fkeydecl.split('__', 1) self.fkattrs = fkattrs.split('__') @@ -94,9 +100,12 @@ class FkeyLookup(object): def __get__(self, obj, klass): if obj is None: - return self # hack required to make Django validate (if obj is - # None, then we're a class, and classes are callable - # ) + """ + hack required to make Django validate (if obj is + None, then we're a class, and classes are callable + ) + """ + return self item = getattr(obj, self.fk) for attr in self.fkattrs: item = getattr(item, attr) @@ -113,14 +122,16 @@ def ProfileInfo(field, short_description, boolean=False): getter.boolean = boolean return getter -User.profile_login_clipper = FkeyLookup("profile__login_clipper", "Login clipper") +User.profile_login_clipper = FkeyLookup("profile__login_clipper", + "Login clipper") User.profile_num = FkeyLookup("profile__num", "Numéro") User.profile_phone = ProfileInfo("phone", "Téléphone") User.profile_occupation = ProfileInfo("occupation", "Occupation") User.profile_departement = ProfileInfo("departement", "Departement") User.profile_mailing_cof = ProfileInfo("mailing_cof", "ML COF", True) User.profile_mailing_bda = ProfileInfo("mailing_bda", "ML BDA", True) -User.profile_mailing_bda_revente = ProfileInfo("mailing_bda_revente", "ML BDA-R", True) +User.profile_mailing_bda_revente = ProfileInfo("mailing_bda_revente", + "ML BDA-R", True) class UserProfileAdmin(UserAdmin): @@ -131,6 +142,7 @@ class UserProfileAdmin(UserAdmin): return False is_buro.short_description = 'Membre du Buro' is_buro.boolean = True + def is_cof(self, obj): try: return obj.profile.is_cof @@ -139,19 +151,18 @@ class UserProfileAdmin(UserAdmin): is_cof.short_description = 'Membre du COF' is_cof.boolean = True list_display = ('profile_num',) + UserAdmin.list_display \ - + ( 'profile_login_clipper','profile_phone','profile_occupation', - 'profile_mailing_cof','profile_mailing_bda', - 'profile_mailing_bda_revente','is_cof','is_buro',) - list_display_links = ('username','email','first_name','last_name') + + ('profile_login_clipper', 'profile_phone', 'profile_occupation', + 'profile_mailing_cof', 'profile_mailing_bda', + 'profile_mailing_bda_revente', 'is_cof', 'is_buro', ) + list_display_links = ('username', 'email', 'first_name', 'last_name') list_filter = UserAdmin.list_filter \ - + ( 'profile__is_cof', 'profile__is_buro', 'profile__mailing_cof', - 'profile__mailing_bda') + + ('profile__is_cof', 'profile__is_buro', 'profile__mailing_cof', + 'profile__mailing_bda') search_fields = UserAdmin.search_fields + ('profile__phone',) inlines = [ - CofProfileInline, - ] + CofProfileInline, + ] -import autocomplete_light def user_unicode(self): if self.first_name and self.last_name: @@ -163,29 +174,29 @@ User.__unicode__ = user_unicode class EventRegistrationAdmin(admin.ModelAdmin): form = autocomplete_light.modelform_factory(EventRegistration, exclude=[]) - list_display = ('__unicode__','event','user','paid') + list_display = ('__unicode__', 'event', 'user', 'paid') list_filter = ('paid',) search_fields = ('user__username', 'user__first_name', 'user__last_name', 'user__email', 'event__title') class PetitCoursAbilityAdmin(admin.ModelAdmin): - list_display = ('user','matiere','niveau','agrege') + list_display = ('user', 'matiere', 'niveau', 'agrege') search_fields = ('user__username', 'user__first_name', 'user__last_name', 'user__email', 'matiere__name', 'niveau') - list_filter = ('matiere','niveau','agrege') + list_filter = ('matiere', 'niveau', 'agrege') class PetitCoursAttributionAdmin(admin.ModelAdmin): - list_display = ('user','demande','matiere','rank',) + list_display = ('user', 'demande', 'matiere', 'rank', ) class PetitCoursAttributionCounterAdmin(admin.ModelAdmin): - list_display = ('user','matiere','count',) + list_display = ('user', 'matiere', 'count', ) list_filter = ('matiere',) search_fields = ('user__username', 'user__first_name', 'user__last_name', 'user__email', 'matiere__name') - actions = ['reset',] + actions = ['reset', ] actions_on_bottom = True def reset(self, request, queryset): @@ -194,9 +205,9 @@ class PetitCoursAttributionCounterAdmin(admin.ModelAdmin): class PetitCoursDemandeAdmin(admin.ModelAdmin): - list_display = ('name','email','agrege_requis','niveau','created', - 'traitee','processed') - list_filter = ('traitee','niveau') + list_display = ('name', 'email', 'agrege_requis', 'niveau', 'created', + 'traitee', 'processed') + list_filter = ('traitee', 'niveau') admin.site.register(Survey, SurveyAdmin) admin.site.register(SurveyQuestion, SurveyQuestionAdmin) @@ -210,6 +221,7 @@ admin.site.register(CustomMail) admin.site.register(PetitCoursSubject) admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin) admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin) -admin.site.register(PetitCoursAttributionCounter, PetitCoursAttributionCounterAdmin) +admin.site.register(PetitCoursAttributionCounter, + PetitCoursAttributionCounterAdmin) admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin) admin.site.register(EventRegistration, EventRegistrationAdmin) diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index e381bed4..4b222f06 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -35,9 +35,12 @@ def autocomplete(request): | Q(username__icontains=bit)) queries['members'] = queries['members'].distinct() queries['users'] = queries['users'].distinct() - usernames = list(queries['members'].values_list('login_clipper', flat='True')) \ - + list(queries['users'].values_list('profile__login_clipper', flat='True')) - queries['clippers'] = queries['clippers'].exclude(username__in=usernames).distinct() + usernames = list(queries['members'].values_list('login_clipper', + flat='True')) \ + + list(queries['users'].values_list('profile__login_clipper', + flat='True')) + queries['clippers'] = queries['clippers'].\ + exclude(username__in=usernames).distinct() # add clippers data.update(queries) diff --git a/gestioncof/autocomplete_light_registry.py b/gestioncof/autocomplete_light_registry.py index f3283f8e..4a2737cb 100644 --- a/gestioncof/autocomplete_light_registry.py +++ b/gestioncof/autocomplete_light_registry.py @@ -2,5 +2,6 @@ import autocomplete_light from django.contrib.auth.models import User -autocomplete_light.register(User, search_fields=('username','first_name','last_name'), +autocomplete_light.register( + User, search_fields=('username', 'first_name', 'last_name'), autocomplete_js_attributes={'placeholder': 'membre...'}) diff --git a/gestioncof/csv_views.py b/gestioncof/csv_views.py index 43c028e0..6ba59d26 100644 --- a/gestioncof/csv_views.py +++ b/gestioncof/csv_views.py @@ -7,7 +7,8 @@ from django.apps import apps def export(qs, fields=None): model = qs.model response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename=%s.csv' % slugify(model.__name__) + response['Content-Disposition'] = 'attachment; filename=%s.csv' %\ + slugify(model.__name__) writer = csv.writer(response) # Write headers to CSV file if fields: @@ -31,10 +32,12 @@ def export(qs, fields=None): return response -def admin_list_export(request, model_name, app_label, queryset=None, fields=None, list_display=True): +def admin_list_export(request, model_name, app_label, queryset=None, + fields=None, list_display=True): """ Put the following line in your urls.py BEFORE your admin include - (r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/', 'util.csv_view.admin_list_export'), + (r'^admin/(?P[\d\w]+)/(?P[\d\w]+)/csv/', + 'util.csv_view.admin_list_export'), """ if not request.user.is_staff: return HttpResponseForbidden() @@ -49,12 +52,17 @@ def admin_list_export(request, model_name, app_label, queryset=None, fields=None fields = None return export(queryset, fields) """ - Create your own change_list.html for your admin view and put something like this in it: + Create your own change_list.html for your admin view and put something + like this in it: {% block object-tools %} {% endblock %} diff --git a/gestioncof/decorators.py b/gestioncof/decorators.py index f442e68e..62c527df 100644 --- a/gestioncof/decorators.py +++ b/gestioncof/decorators.py @@ -9,7 +9,8 @@ def is_cof(user): return False cof_required = user_passes_test(lambda u: is_cof(u)) -cof_required_customdenied = user_passes_test(lambda u: is_cof(u), login_url="cof-denied") +cof_required_customdenied = user_passes_test(lambda u: is_cof(u), + login_url="cof-denied") def is_buro(user): diff --git a/gestioncof/forms.py b/gestioncof/forms.py index cfe1aa62..8cfd6b9f 100644 --- a/gestioncof/forms.py +++ b/gestioncof/forms.py @@ -26,16 +26,20 @@ class EventForm(forms.Form): choices[choice.event_option.id].append(choice.id) all_choices = choices for option in event.options.all(): - choices = [(choice.id, choice.value) for choice in option.choices.all()] + choices = [(choice.id, choice.value) + for choice in option.choices.all()] if option.multi_choices: - initial = [] if option.id not in all_choices else all_choices[option.id] - field = forms.MultipleChoiceField(label=option.name, - choices=choices, - widget=CheckboxSelectMultiple, - required=False, - initial=initial) + initial = [] if option.id not in all_choices \ + else all_choices[option.id] + field = forms.MultipleChoiceField( + label=option.name, + choices=choices, + widget=CheckboxSelectMultiple, + required=False, + initial=initial) else: - initial = None if option.id not in all_choices else all_choices[option.id][0] + initial = None if option.id not in all_choices \ + else all_choices[option.id][0] field = forms.ChoiceField(label=option.name, choices=choices, widget=RadioSelect, @@ -63,16 +67,20 @@ class SurveyForm(forms.Form): else: answers[answer.survey_question.id].append(answer.id) for question in survey.questions.all(): - choices = [(answer.id, answer.answer) for answer in question.answers.all()] + choices = [(answer.id, answer.answer) + for answer in question.answers.all()] if question.multi_answers: - initial = [] if question.id not in answers else answers[question.id] - field = forms.MultipleChoiceField(label=question.question, - choices=choices, - widget=CheckboxSelectMultiple, - required=False, - initial=initial) + initial = [] if question.id not in answers\ + else answers[question.id] + field = forms.MultipleChoiceField( + label=question.question, + choices=choices, + widget=CheckboxSelectMultiple, + required=False, + initial=initial) else: - initial = None if question.id not in answers else answers[question.id][0] + initial = None if question.id not in answers\ + else answers[question.id][0] field = forms.ChoiceField(label=question.question, choices=choices, widget=RadioSelect, @@ -94,15 +102,18 @@ class SurveyStatusFilterForm(forms.Form): for question in survey.questions.all(): for answer in question.answers.all(): name = "question_%d_answer_%d" % (question.id, answer.id) - if self.is_bound and self.data.get(self.add_prefix(name), None): + if self.is_bound and\ + self.data.get(self.add_prefix(name), None): initial = self.data.get(self.add_prefix(name), None) else: initial = "none" - field = forms.ChoiceField(label="%s : %s" % (question.question, answer.answer), - choices=[("yes", "yes"), ("no", "no"), ("none", "none")], - widget=TriStateCheckbox, - required=False, - initial=initial) + field = forms.ChoiceField( + label="%s : %s" % + (question.question, answer.answer), + choices=[("yes", "yes"), ("no", "no"), ("none", "none")], + widget=TriStateCheckbox, + required=False, + initial=initial) field.question_id = question.id field.answer_id = answer.id self.fields[name] = field @@ -110,7 +121,8 @@ class SurveyStatusFilterForm(forms.Form): def filters(self): for name, value in self.cleaned_data.items(): if name.startswith('question_'): - yield (self.fields[name].question_id, self.fields[name].answer_id, value) + yield (self.fields[name].question_id, + self.fields[name].answer_id, value) class EventStatusFilterForm(forms.Form): @@ -120,15 +132,17 @@ class EventStatusFilterForm(forms.Form): for option in event.options.all(): for choice in option.choices.all(): name = "option_%d_choice_%d" % (option.id, choice.id) - if self.is_bound and self.data.get(self.add_prefix(name), None): + if self.is_bound and\ + self.data.get(self.add_prefix(name), None): initial = self.data.get(self.add_prefix(name), None) else: initial = "none" - field = forms.ChoiceField(label="%s : %s" % (option.name, choice.value), - choices=[("yes", "yes"), ("no", "no"), ("none", "none")], - widget=TriStateCheckbox, - required=False, - initial=initial) + field = forms.ChoiceField( + label="%s : %s" % (option.name, choice.value), + choices=[("yes", "yes"), ("no", "no"), ("none", "none")], + widget=TriStateCheckbox, + required=False, + initial=initial) field.option_id = option.id field.choice_id = choice.id self.fields[name] = field @@ -139,7 +153,8 @@ class EventStatusFilterForm(forms.Form): else: initial = "none" field = forms.ChoiceField(label="Événement payé", - choices=[("yes", "yes"), ("no", "no"), ("none", "none")], + choices=[("yes", "yes"), ("no", "no"), + ("none", "none")], widget=TriStateCheckbox, required=False, initial=initial) @@ -148,7 +163,8 @@ class EventStatusFilterForm(forms.Form): def filters(self): for name, value in self.cleaned_data.items(): if name.startswith('option_'): - yield (self.fields[name].option_id, self.fields[name].choice_id, value) + yield (self.fields[name].option_id, + self.fields[name].choice_id, value) elif name == "event_has_paid": yield ("has_paid", None, value) @@ -179,7 +195,8 @@ class UserProfileForm(forms.ModelForm): class Meta: model = CofProfile - fields = ("phone", "mailing_cof", "mailing_bda", "mailing_bda_revente", ) + fields = ("phone", "mailing_cof", "mailing_bda", + "mailing_bda_revente", ) class RegistrationUserForm(forms.ModelForm): @@ -231,7 +248,9 @@ class RegistrationProfileForm(forms.ModelForm): class Meta: model = CofProfile - fields = ("login_clipper", "num", "phone", "occupation", "departement", "is_cof", "type_cotiz", "mailing_cof", "mailing_bda", "mailing_bda_revente", "comments") + fields = ("login_clipper", "num", "phone", "occupation", + "departement", "is_cof", "type_cotiz", "mailing_cof", + "mailing_bda", "mailing_bda_revente", "comments") STATUS_CHOICES = (('no', 'Non'), ('wait', 'Oui mais attente paiement'), @@ -239,13 +258,16 @@ STATUS_CHOICES = (('no', 'Non'), class AdminEventForm(forms.Form): - status = forms.ChoiceField(label="Inscription", choices=STATUS_CHOICES, widget=RadioSelect) + status = forms.ChoiceField(label="Inscription", + choices=STATUS_CHOICES, widget=RadioSelect) def __init__(self, *args, **kwargs): event = kwargs.pop("event") self.event = event registration = kwargs.pop("current_registration", None) - current_choices = registration.options.all() if registration is not None else [] + current_choices = \ + registration.options.all() if registration is not None\ + else [] paid = kwargs.pop("paid", None) if paid is True: kwargs["initial"] = {"status": "paid"} @@ -262,16 +284,20 @@ class AdminEventForm(forms.Form): choices[choice.event_option.id].append(choice.id) all_choices = choices for option in event.options.all(): - choices = [(choice.id, choice.value) for choice in option.choices.all()] + choices = [(choice.id, choice.value) + for choice in option.choices.all()] if option.multi_choices: - initial = [] if option.id not in all_choices else all_choices[option.id] - field = forms.MultipleChoiceField(label=option.name, - choices=choices, - widget=CheckboxSelectMultiple, - required=False, - initial=initial) + initial = [] if option.id not in all_choices\ + else all_choices[option.id] + field = forms.MultipleChoiceField( + label=option.name, + choices=choices, + widget=CheckboxSelectMultiple, + required=False, + initial=initial) else: - initial = None if option.id not in all_choices else all_choices[option.id][0] + initial = None if option.id not in all_choices\ + else all_choices[option.id][0] field = forms.ChoiceField(label=option.name, choices=choices, widget=RadioSelect, @@ -283,10 +309,12 @@ class AdminEventForm(forms.Form): initial = commentfield.default if registration is not None: try: - initial = registration.comments.get(commentfield=commentfield).content + initial = registration.comments.\ + get(commentfield=commentfield).content except EventCommentValue.DoesNotExist: pass - widget = forms.Textarea if commentfield.fieldtype == "text" else forms.TextInput + widget = forms.Textarea if commentfield.fieldtype == "text" \ + else forms.TextInput field = forms.CharField(label=commentfield.name, widget=widget, required=False, diff --git a/gestioncof/models.py b/gestioncof/models.py index bac5ad62..a564a747 100644 --- a/gestioncof/models.py +++ b/gestioncof/models.py @@ -41,21 +41,28 @@ class CofProfile(models.Model): num = models.IntegerField("Numéro d'adhérent", blank=True, default=0) phone = models.CharField("Téléphone", max_length=20, blank=True) occupation = models.CharField(_(u"Occupation"), - default="1A", - choices=OCCUPATION_CHOICES, - max_length=choices_length(OCCUPATION_CHOICES)) - departement = models.CharField(_(u"Département"), max_length=50, blank=True) + default="1A", + choices=OCCUPATION_CHOICES, + max_length=choices_length( + OCCUPATION_CHOICES)) + departement = models.CharField(_(u"Département"), max_length=50, + blank=True) type_cotiz = models.CharField(_(u"Type de cotisation"), - default="normalien", - max_length=choices_length(TYPE_COTIZ_CHOICES)) + default="normalien", + max_length=choices_length( + TYPE_COTIZ_CHOICES)) mailing_cof = models.BooleanField("Recevoir les mails COF", default=False) mailing_bda = models.BooleanField("Recevoir les mails BdA", default=False) - mailing_bda_revente = models.BooleanField("Recevoir les mails de revente de places BdA", default=False) - comments = models.TextField("Commentaires visibles uniquement par le Buro", blank=True) + mailing_bda_revente = models.BooleanField( + "Recevoir les mails de revente de places BdA", default=False) + comments = models.TextField( + "Commentaires visibles uniquement par le Buro", blank=True) is_buro = models.BooleanField("Membre du Burô", default=False) - petits_cours_accept = models.BooleanField("Recevoir des petits cours", default=False) - petits_cours_remarques = models.TextField(_(u"Remarques et précisions pour les petits cours"), - blank=True, default="") + petits_cours_accept = models.BooleanField( + "Recevoir des petits cours", default=False) + petits_cours_remarques = models.TextField( + _(u"Remarques et précisions pour les petits cours"), + blank=True, default="") class Meta: verbose_name = "Profil COF" @@ -82,7 +89,8 @@ class CustomMail(models.Model): shortname = models.SlugField(max_length=50, blank=False) title = models.CharField("Titre", max_length=200, blank=False) content = models.TextField("Contenu", blank=False) - comments = models.TextField("Informations contextuelles sur le mail", blank=True) + comments = models.TextField("Informations contextuelles sur le mail", + blank=True) class Meta: verbose_name = "Mails personnalisables" @@ -97,7 +105,8 @@ class Event(models.Model): start_date = models.DateField("Date de début", blank=True, null=True) end_date = models.DateField("Date de fin", blank=True, null=True) description = models.TextField("Description", blank=True) - registration_open = models.BooleanField("Inscriptions ouvertes", default=True) + registration_open = models.BooleanField("Inscriptions ouvertes", + default=True) old = models.BooleanField("Archiver (événement fini)", default=False) class Meta: @@ -110,7 +119,8 @@ class Event(models.Model): class EventCommentField(models.Model): event = models.ForeignKey(Event, related_name="commentfields") name = models.CharField("Champ", max_length=200) - fieldtype = models.CharField("Type", max_length=10, choices=TYPE_COMMENT_FIELD, default="text") + fieldtype = models.CharField("Type", max_length=10, + choices=TYPE_COMMENT_FIELD, default="text") default = models.TextField("Valeur par défaut", blank=True) class Meta: @@ -122,7 +132,8 @@ class EventCommentField(models.Model): class EventCommentValue(models.Model): commentfield = models.ForeignKey(EventCommentField, related_name="values") - registration = models.ForeignKey("EventRegistration", related_name="comments") + registration = models.ForeignKey("EventRegistration", + related_name="comments") content = models.TextField("Contenu", blank=True, null=True) @@ -153,7 +164,8 @@ class EventRegistration(models.Model): user = models.ForeignKey(User) event = models.ForeignKey(Event) options = models.ManyToManyField(EventOptionChoice) - filledcomments = models.ManyToManyField(EventCommentField, through=EventCommentValue) + filledcomments = models.ManyToManyField(EventCommentField, + through=EventCommentValue) paid = models.BooleanField("A payé", default=False) class Meta: @@ -161,7 +173,8 @@ class EventRegistration(models.Model): unique_together = ("user", "event") def __unicode__(self): - return u"Inscription de %s à %s" % (unicode(self.user), unicode(self.event.title)) + return u"Inscription de %s à %s" % (unicode(self.user), + unicode(self.event.title)) class Survey(models.Model): @@ -203,7 +216,8 @@ class SurveyQuestionAnswer(models.Model): class SurveyAnswer(models.Model): user = models.ForeignKey(User) survey = models.ForeignKey(Survey) - answers = models.ManyToManyField(SurveyQuestionAnswer, related_name="selected_by") + answers = models.ManyToManyField(SurveyQuestionAnswer, + related_name="selected_by") class Meta: verbose_name = "Réponses" diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index 47339a4e..a9aede0c 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -4,8 +4,9 @@ from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ -def choices_length (choices): - return reduce (lambda m, choice: max (m, len (choice[0])), choices, 0) + +def choices_length(choices): + return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0) LEVELS_CHOICES = ( ('college', _(u"Collège")), @@ -16,6 +17,7 @@ LEVELS_CHOICES = ( ('other', _(u"Autre (préciser dans les commentaires)")), ) + class PetitCoursSubject(models.Model): name = models.CharField(_(u"Matière"), max_length=30) users = models.ManyToManyField(User, related_name="petits_cours_matieres", @@ -28,12 +30,13 @@ class PetitCoursSubject(models.Model): def __unicode__(self): return self.name + class PetitCoursAbility(models.Model): user = models.ForeignKey(User) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière")) - niveau = models.CharField (_(u"Niveau"), - choices=LEVELS_CHOICES, - max_length=choices_length (LEVELS_CHOICES)) + niveau = models.CharField(_(u"Niveau"), + choices=LEVELS_CHOICES, + max_length=choices_length(LEVELS_CHOICES)) agrege = models.BooleanField(_(u"Agrégé"), default=False) class Meta: @@ -41,7 +44,9 @@ class PetitCoursAbility(models.Model): verbose_name_plural = "Compétences des petits cours" def __unicode__(self): - return u"%s - %s - %s" % (self.user.username, self.matiere, self.niveau) + return u"%s - %s - %s" % (self.user.username, + self.matiere, self.niveau) + class PetitCoursDemande(models.Model): name = models.CharField(_(u"Nom/prénom"), max_length=200) @@ -49,28 +54,28 @@ class PetitCoursDemande(models.Model): phone = models.CharField(_(u"Téléphone (facultatif)"), max_length=20, blank=True) quand = models.CharField( - _(u"Quand ?"), - help_text=_(u"Indiquez ici la période désirée pour les petits" \ - + " cours (vacances scolaires, semaine, week-end)."), - max_length=300, blank=True) + _(u"Quand ?"), + help_text=_(u"Indiquez ici la période désirée pour les petits" + " cours (vacances scolaires, semaine, week-end)."), + max_length=300, blank=True) freq = models.CharField( - _(u"Fréquence"), - help_text=_(u"Indiquez ici la fréquence envisagée " \ + _(u"Fréquence"), + help_text=_(u"Indiquez ici la fréquence envisagée " + "(hebdomadaire, 2 fois par semaine, ...)"), - max_length=300, blank=True) + max_length=300, blank=True) lieu = models.CharField( - _(u"Lieu (si préférence)"), - help_text=_(u"Si vous avez avez une préférence sur le lieu."), - max_length=300, blank=True) + _(u"Lieu (si préférence)"), + help_text=_(u"Si vous avez avez une préférence sur le lieu."), + max_length=300, blank=True) matieres = models.ManyToManyField( - PetitCoursSubject, verbose_name=_(u"Matières"), - related_name="demandes") + PetitCoursSubject, verbose_name=_(u"Matières"), + related_name="demandes") agrege_requis = models.BooleanField(_(u"Agrégé requis"), default=False) - niveau = models.CharField (_(u"Niveau"), - default="", - choices=LEVELS_CHOICES, - max_length=choices_length (LEVELS_CHOICES)) + niveau = models.CharField(_(u"Niveau"), + default="", + choices=LEVELS_CHOICES, + max_length=choices_length(LEVELS_CHOICES)) remarques = models.TextField(_(u"Remarques et précisions"), blank=True) @@ -85,7 +90,9 @@ class PetitCoursDemande(models.Model): verbose_name_plural = "Demandes de petits cours" def __unicode__(self): - return u"Demande %d du %s" % (self.id, self.created.strftime("%d %b %Y")) + return u"Demande %d du %s" % (self.id, + self.created.strftime("%d %b %Y")) + class PetitCoursAttribution(models.Model): user = models.ForeignKey(User) @@ -94,7 +101,7 @@ class PetitCoursAttribution(models.Model): date = models.DateTimeField(_(u"Date d'attribution"), auto_now_add=True) rank = models.IntegerField("Rang dans l'email") selected = models.BooleanField(_(u"Sélectionné par le demandeur"), - default=False) + default=False) class Meta: verbose_name = "Attribution de petits cours" @@ -102,7 +109,8 @@ class PetitCoursAttribution(models.Model): def __unicode__(self): return u"Attribution de la demande %d à %s pour %s" \ - % (self.demande.id, self.user.username, self.matiere) + % (self.demande.id, self.user.username, self.matiere) + class PetitCoursAttributionCounter(models.Model): user = models.ForeignKey(User) @@ -115,5 +123,4 @@ class PetitCoursAttributionCounter(models.Model): def __unicode__(self): return u"%d demandes envoyées à %s pour %s" \ - % (self.count, self.user.username, self.matiere) - + % (self.count, self.user.username, self.matiere) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 534632af..a4353b09 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -56,10 +56,12 @@ def details(request, demande_id): def _get_attrib_counter(user, matiere): - counter, created = PetitCoursAttributionCounter.objects.get_or_create(user=user, - matiere=matiere) + counter, created = PetitCoursAttributionCounter.\ + objects.get_or_create(user=user, matiere=matiere) if created: - mincount = PetitCoursAttributionCounter.objects.filter(matiere=matiere).exclude(user=user).all().aggregate(Min('count')) + mincount = PetitCoursAttributionCounter.objects.\ + filter(matiere=matiere).exclude(user=user).all().\ + aggregate(Min('count')) counter.count = mincount['count__min'] counter.save() return counter @@ -67,14 +69,15 @@ def _get_attrib_counter(user, matiere): def _get_demande_candidates(demande, redo=False): for matiere in demande.matieres.all(): - candidates = PetitCoursAbility.objects.filter(matiere=matiere, niveau=demande.niveau) + candidates = PetitCoursAbility.objects.filter(matiere=matiere, + niveau=demande.niveau) candidates = candidates.filter(user__profile__is_cof=True, user__profile__petits_cours_accept=True) if demande.agrege_requis: candidates = candidates.filter(agrege=True) if redo: - attributions = PetitCoursAttribution.objects.filter(demande=demande, - matiere=matiere).all() + attributions = PetitCoursAttribution.objects.\ + filter(demande=demande, matiere=matiere).all() for attrib in attributions: candidates = candidates.exclude(user=attrib.user) candidates = candidates.order_by('?').select_related().all() @@ -131,7 +134,11 @@ def _finalize_traitement(request, demande, proposals, proposed_for, mainmail = render_template("petits-cours-mail-demandeur.txt", {"proposals": proposals, "unsatisfied": unsatisfied, - "extra": ""}) + "extra": + '' + }) return render(request, "traitement_demande_petit_cours.html", {"demande": demande, "unsatisfied": unsatisfied, @@ -139,16 +146,18 @@ def _finalize_traitement(request, demande, proposals, proposed_for, "proposed_for": proposed_for, "proposed_mails": proposed_mails, "mainmail": mainmail, - "attribdata": base64.b64encode(simplejson.dumps(attribdata)), + "attribdata": + base64.b64encode(simplejson.dumps(attribdata)), "redo": redo, "errors": errors, - }) + }) def _generate_eleve_email(demande, proposed_for): proposed_mails = [] for user, matieres in proposed_for: - msg = render_template("petits-cours-mail-eleve.txt", {"demande": demande, "matieres": matieres}) + msg = render_template("petits-cours-mail-eleve.txt", + {"demande": demande, "matieres": matieres}) proposed_mails.append((user, msg)) return proposed_mails @@ -167,15 +176,18 @@ def _traitement_other_preparing(request, demande): attribdata[matiere.id] = [] proposals[matiere] = [] for choice_id in range(min(3, len(candidates))): - choice = int(request.POST["proposal-%d-%d" % (matiere.id, choice_id)]) + choice = int( + request.POST["proposal-%d-%d" % (matiere.id, choice_id)]) if choice == -1: continue if choice not in candidates: - errors.append(u"Choix invalide pour la proposition %d en %s" % (choice_id + 1, matiere)) + errors.append(u"Choix invalide pour la proposition %d" + "en %s" % (choice_id + 1, matiere)) continue user = candidates[choice] if user in proposals[matiere]: - errors.append(u"La proposition %d en %s est un doublon" % (choice_id + 1, matiere)) + errors.append(u"La proposition %d en %s est un doublon" % + (choice_id + 1, matiere)) continue proposals[matiere].append(user) attribdata[matiere.id].append(user.id) @@ -186,10 +198,14 @@ def _traitement_other_preparing(request, demande): if not proposals[matiere]: errors.append(u"Aucune proposition pour %s" % (matiere,)) elif len(proposals[matiere]) < 3: - errors.append(u"Seulement %d proposition%s pour %s" % (len(proposals[matiere]), "s" if len(proposals[matiere]) > 1 else "", matiere)) + errors.append(u"Seulement %d proposition%s pour %s" % + (len(proposals[matiere]), "s" + if len(proposals[matiere]) > 1 else "", + matiere)) else: unsatisfied.append(matiere) - return _finalize_traitement(request, demande, proposals, proposed_for, unsatisfied, attribdata, errors=errors) + return _finalize_traitement(request, demande, proposals, proposed_for, + unsatisfied, attribdata, errors=errors) def _traitement_other(request, demande, redo): @@ -229,7 +245,7 @@ def _traitement_other(request, demande, redo): "unsatisfied": unsatisfied, "proposals": proposals, "proposed_for": proposed_for, - }) + }) def _traitement_post(request, demande): @@ -270,13 +286,15 @@ def _traitement_post(request, demande): mails_to_send.append(msg) mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail, frommail, [demande.email], - [bccaddress], headers={'Reply-To': replyto})) + [bccaddress], + headers={'Reply-To': replyto})) connection = mail.get_connection(fail_silently=True) connection.send_messages(mails_to_send) lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User) for matiere in proposals: for rank, user in enumerate(proposals[matiere]): - counter = PetitCoursAttributionCounter.objects.get(user=user, matiere=matiere) + counter = PetitCoursAttributionCounter.objects.get(user=user, + matiere=matiere) counter.count += 1 counter.save() attrib = PetitCoursAttribution(user=user, matiere=matiere, @@ -290,14 +308,15 @@ def _traitement_post(request, demande): return render(request, "traitement_demande_petit_cours_success.html", {"demande": demande, "redo": redo, - }) + }) class BaseMatieresFormSet(BaseInlineFormSet): def clean(self): super(BaseMatieresFormSet, self).clean() if any(self.errors): - # Don't bother validating the formset unless each form is valid on its own + # Don't bother validating the formset unless each form is + # valid on its own return matieres = [] for i in range(0, self.total_form_count()): @@ -308,7 +327,9 @@ class BaseMatieresFormSet(BaseInlineFormSet): niveau = form.cleaned_data['niveau'] delete = form.cleaned_data['DELETE'] if not delete and (matiere, niveau) in matieres: - raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour la même matiere avec le même niveau.") + raise forms.ValidationError( + "Vous ne pouvez pas vous inscrire deux fois pour la " + "même matiere avec le même niveau.") matieres.append((matiere, niveau)) @@ -318,7 +339,8 @@ def inscription(request): if not profile.is_cof: return redirect("cof-denied") MatieresFormSet = inlineformset_factory(User, PetitCoursAbility, - fields=("matiere", "niveau", "agrege",), + fields=("matiere", "niveau", + "agrege",), formset=BaseMatieresFormSet) success = False if request.method == "POST": @@ -328,8 +350,10 @@ def inscription(request): profile.petits_cours_accept = "receive_proposals" in request.POST profile.petits_cours_remarques = request.POST["remarques"] profile.save() - lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User, PetitCoursSubject) - abilities = PetitCoursAbility.objects.filter(user=request.user).all() + lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User, + PetitCoursSubject) + abilities = PetitCoursAbility.objects.\ + filter(user=request.user).all() for ability in abilities: counter = _get_attrib_counter(ability.user, ability.matiere) unlock_tables() @@ -337,7 +361,11 @@ def inscription(request): formset = MatieresFormSet(instance=request.user) else: formset = MatieresFormSet(instance=request.user) - return render(request, "inscription-petit-cours.html", {"formset": formset, "success": success, "receive_proposals": profile.petits_cours_accept, "remarques": profile.petits_cours_remarques}) + return render(request, "inscription-petit-cours.html", + {"formset": formset, "success": success, + "receive_proposals": profile.petits_cours_accept, + "remarques": profile.petits_cours_remarques}) + class DemandeForm(ModelForm): captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'}) @@ -348,7 +376,8 @@ class DemandeForm(ModelForm): class Meta: model = PetitCoursDemande - fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu', 'matieres', 'agrege_requis', 'niveau', 'remarques') + fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu', + 'matieres', 'agrege_requis', 'niveau', 'remarques') widgets = {'matieres': forms.CheckboxSelectMultiple} @@ -362,7 +391,8 @@ def demande(request): success = True else: form = DemandeForm() - return render(request, "demande-petit-cours.html", {"form": form, "success": success}) + return render(request, "demande-petit-cours.html", {"form": form, + "success": success}) @csrf_exempt @@ -375,4 +405,5 @@ def demande_raw(request): success = True else: form = DemandeForm() - return render(request, "demande-petit-cours-raw.html", {"form": form, "success": success}) + return render(request, "demande-petit-cours-raw.html", + {"form": form, "success": success}) diff --git a/gestioncof/urls.py b/gestioncof/urls.py index a8a38dbc..787dd80f 100644 --- a/gestioncof/urls.py +++ b/gestioncof/urls.py @@ -19,7 +19,8 @@ petitcours_patterns = [ name='petits-cours-demande-raw'), url(r'^demandes$', DemandeListView.as_view(), name='petits-cours-demandes-list'), - url(r'^demandes/(?P\d+)$', 'gestioncof.petits_cours_views.details', + url(r'^demandes/(?P\d+)$', + 'gestioncof.petits_cours_views.details', name='petits-cours-demande-details'), url(r'^demandes/(?P\d+)/traitement$', 'gestioncof.petits_cours_views.traitement', @@ -38,5 +39,3 @@ events_patterns = [ url(r'^(?P\d+)$', 'gestioncof.views.event'), url(r'^(?P\d+)/status$', 'gestioncof.views.event_status'), ] - - diff --git a/gestioncof/views.py b/gestioncof/views.py index cdf758b2..fb9fbcb8 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -8,8 +8,10 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.views import login as django_login_view from django.contrib.auth.models import User -from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, SurveyQuestionAnswer -from gestioncof.models import Event, EventRegistration, EventOption, EventOptionChoice +from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \ + SurveyQuestionAnswer +from gestioncof.models import Event, EventRegistration, EventOption, \ + EventOptionChoice from gestioncof.models import EventCommentField, EventCommentValue from gestioncof.shared import send_custom_mail from gestioncof.models import CofProfile, Clipper @@ -25,8 +27,10 @@ from bda.models import Tirage 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(), + "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) @@ -44,9 +48,11 @@ def login_ext(request): if not user.has_usable_password() or user.password in ("", "!"): profile, created = CofProfile.objects.get_or_create(user=user) if profile.login_clipper: - return render(request, "error.html", {"error_type": "use_clipper_login"}) + return render(request, "error.html", + {"error_type": "use_clipper_login"}) else: - return render(request, "error.html", {"error_type": "no_password"}) + return render(request, "error.html", + {"error_type": "no_password"}) except User.DoesNotExist: pass return django_login_view(request, template_name='login.html') @@ -75,7 +81,8 @@ def survey(request, survey_id): form = SurveyForm(request.POST, survey=survey) if request.POST.get('delete'): try: - current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey) + current_answer = SurveyAnswer.objects.get(user=request.user, + survey=survey) current_answer.delete() current_answer = None except SurveyAnswer.DoesNotExist: @@ -87,7 +94,8 @@ def survey(request, survey_id): if form.is_valid(): all_answers = [] for question_id, answers_ids in form.answers(): - question = get_object_or_404(SurveyQuestion, id=question_id, + question = get_object_or_404(SurveyQuestion, + id=question_id, survey=survey) if type(answers_ids) != list: answers_ids = [answers_ids] @@ -102,21 +110,28 @@ def survey(request, survey_id): survey_question=question) all_answers.append(answer) try: - current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey) + current_answer = SurveyAnswer.objects.get( + user=request.user, survey=survey) except SurveyAnswer.DoesNotExist: - current_answer = SurveyAnswer(user=request.user, survey=survey) + current_answer = SurveyAnswer(user=request.user, + survey=survey) current_answer.save() current_answer.answers = all_answers current_answer.save() success = True else: try: - current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey) - form = SurveyForm(survey=survey, current_answers=current_answer.answers) + current_answer = SurveyAnswer.objects.get(user=request.user, + survey=survey) + form = SurveyForm(survey=survey, + current_answers=current_answer.answers) except SurveyAnswer.DoesNotExist: current_answer = None form = SurveyForm(survey=survey) - return render(request, "survey.html", {"survey": survey, "form": form, "success": success, "deleted": deleted, "current_answer": current_answer}) + return render(request, "survey.html", {"survey": survey, "form": form, + "success": success, + "deleted": deleted, + "current_answer": current_answer}) def get_event_form_choices(event, form): @@ -138,14 +153,16 @@ def get_event_form_choices(event, form): all_choices.append(choice) return all_choices + def update_event_form_comments(event, form, registration): for commentfield_id, value in form.comments(): field = get_object_or_404(EventCommentField, id=commentfield_id, event=event) if value == field.default: continue - (storage, _) = EventCommentValue.objects.get_or_create(commentfield=field, - registration=registration) + (storage, _) = EventCommentValue.objects.get_or_create( + commentfield=field, + registration=registration) storage.content = value storage.save() @@ -160,17 +177,23 @@ def event(request, event_id): form = EventForm(request.POST, event=event) if form.is_valid(): all_choices = get_event_form_choices(event, form) - (current_registration, _) = EventRegistration.objects.get_or_create(user=request.user, event=event) + (current_registration, _) = \ + EventRegistration.objects.get_or_create(user=request.user, + event=event) current_registration.options = all_choices current_registration.save() success = True else: try: - current_registration = EventRegistration.objects.get(user=request.user, event=event) - form = EventForm(event=event, current_choices=current_registration.options) + current_registration = \ + EventRegistration.objects.get(user=request.user, event=event) + form = EventForm(event=event, + current_choices=current_registration.options) except EventRegistration.DoesNotExist: form = EventForm(event=event) - return render(request, "event.html", {"event": event, "form": form, "success": success}) + return render(request, "event.html", + {"event": event, "form": form, "success": success}) + def clean_post_for_status(initial): d = initial.copy() @@ -180,6 +203,7 @@ def clean_post_for_status(initial): d[k[3:]] = v return d + @buro_required def event_status(request, event_id): event = get_object_or_404(Event, id=event_id) @@ -192,15 +216,19 @@ def event_status(request, event_id): if value == "yes": registrations_query = registrations_query.filter(paid=True) elif value == "no": - registrations_query = registrations_query.filter(paid=False) + registrations_query = registrations_query.filter( + paid=False) continue - choice = get_object_or_404(EventOptionChoice, id=choice_id, event_option__id=option_id) + choice = get_object_or_404(EventOptionChoice, id=choice_id, + event_option__id=option_id) if value == "none": continue if value == "yes": - registrations_query = registrations_query.filter(options__id__exact=choice.id) + registrations_query = registrations_query.filter( + options__id__exact=choice.id) elif value == "no": - registrations_query = registrations_query.exclude(options__id__exact=choice.id) + registrations_query = registrations_query.exclude( + options__id__exact=choice.id) user_choices = registrations_query.prefetch_related("user").all() options = EventOption.objects.filter(event=event).all() choices_count = {} @@ -210,7 +238,10 @@ def event_status(request, event_id): for user_choice in user_choices: for choice in user_choice.options.all(): choices_count[choice.id] += 1 - return render(request, "event_status.html", {"event": event, "user_choices": user_choices, "options": options, "choices_count": choices_count, "form": form}) + return render(request, "event_status.html", + {"event": event, "user_choices": user_choices, + "options": options, "choices_count": choices_count, + "form": form}) @buro_required @@ -221,13 +252,16 @@ def survey_status(request, survey_id): form = SurveyStatusFilterForm(post_data or None, survey=survey) if form.is_valid(): for question_id, answer_id, value in form.filters(): - answer = get_object_or_404(SurveyQuestionAnswer, id=answer_id, survey_question__id=question_id) + answer = get_object_or_404(SurveyQuestionAnswer, id=answer_id, + survey_question__id=question_id) if value == "none": continue if value == "yes": - answers_query = answers_query.filter(answers__id__exact=answer.id) + answers_query = answers_query.filter( + answers__id__exact=answer.id) elif value == "no": - answers_query = answers_query.exclude(answers__id__exact=answer.id) + answers_query = answers_query.exclude( + answers__id__exact=answer.id) user_answers = answers_query.prefetch_related("user").all() questions = SurveyQuestion.objects.filter(survey=survey).all() answers_count = {} @@ -237,7 +271,10 @@ def survey_status(request, survey_id): for user_answer in user_answers: for answer in user_answer.answers.all(): answers_count[answer.id] += 1 - return render(request, "survey_status.html", {"survey": survey, "user_answers": user_answers, "questions": questions, "answers_count": answers_count, "form": form}) + return render(request, "survey_status.html", + {"survey": survey, "user_answers": user_answers, + "questions": questions, "answers_count": answers_count, + "form": form}) @login_required @@ -272,7 +309,8 @@ def registration_form(request, login_clipper=None, username=None): user_form = RegistrationUserForm() profile_form = RegistrationProfileForm() user_form.fields['username'].initial = login_clipper - user_form.fields['email'].initial = login_clipper + "@clipper.ens.fr" + user_form.fields['email'].initial = \ + login_clipper + "@clipper.ens.fr" profile_form.fields['login_clipper'].initial = login_clipper if clipper.fullname: bits = clipper.fullname.split(" ") @@ -291,7 +329,10 @@ def registration_form(request, login_clipper=None, username=None): # new user user_form = RegistrationUserForm() profile_form = RegistrationProfileForm() - return render(request, "registration_form.html", {"user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper}) + return render(request, "registration_form.html", + {"user_form": user_form, "profile_form": profile_form, + "member": member, "login_clipper": login_clipper}) + @buro_required def registration_form2(request, login_clipper=None, username=None): @@ -309,7 +350,8 @@ def registration_form2(request, login_clipper=None, username=None): profile_form = RegistrationProfileForm() event_forms = [AdminEventForm(event=event) for event in events] user_form.fields['username'].initial = login_clipper - user_form.fields['email'].initial = login_clipper + "@clipper.ens.fr" + user_form.fields['email'].initial = \ + login_clipper + "@clipper.ens.fr" profile_form.fields['login_clipper'].initial = login_clipper if clipper.fullname: bits = clipper.fullname.split(" ") @@ -327,8 +369,12 @@ def registration_form2(request, login_clipper=None, username=None): event_forms = [] for event in events: try: - current_registration = EventRegistration.objects.get(user=member, event=event) - form = AdminEventForm(event=event, current_registration=current_registration, paid=current_registration.paid) + current_registration = EventRegistration.objects.get( + user=member, event=event) + form = AdminEventForm( + event=event, + current_registration=current_registration, + paid=current_registration.paid) except EventRegistration.DoesNotExist: form = AdminEventForm(event=event) event_forms.append(form) @@ -337,7 +383,10 @@ def registration_form2(request, login_clipper=None, username=None): user_form = RegistrationUserForm() profile_form = RegistrationProfileForm() event_forms = [AdminEventForm(event=event) for event in events] - return render(request, "registration_form.html", {"user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper, "event_forms": event_forms}) + return render(request, "registration_form.html", + {"user_form": user_form, "profile_form": profile_form, + "member": member, "login_clipper": login_clipper, + "event_forms": event_forms}) @buro_required @@ -350,7 +399,8 @@ def registration(request): user_form = RegistrationUserForm(request_dict) profile_form = RegistrationProfileForm(request_dict) events = Event.objects.filter(old=False).all() - event_forms = [AdminEventForm(request_dict, event=event) for event in events] + event_forms = \ + [AdminEventForm(request_dict, event=event) for event in events] user_form.is_valid() profile_form.is_valid() for event_form in event_forms: @@ -363,7 +413,8 @@ def registration(request): member = User.objects.filter(username=username).get() (profile, _) = CofProfile.objects.get_or_create(user=member) user_form = RegistrationUserForm(request_dict, instance=member) - profile_form = RegistrationProfileForm(request_dict, instance=profile) + profile_form = RegistrationProfileForm(request_dict, + instance=profile) except User.DoesNotExist: try: clipper = Clipper.objects.filter(username=username).get() @@ -376,12 +427,14 @@ def registration(request): if form.cleaned_data['status'] == 'no': continue all_choices = get_event_form_choices(form.event, form) - if user_form.is_valid() and profile_form.is_valid() and not any([not form.is_valid() for form in event_forms]): + if user_form.is_valid() and profile_form.is_valid() and \ + not any([not form.is_valid() for form in event_forms]): member = user_form.save() (profile, _) = CofProfile.objects.get_or_create(user=member) was_cof = profile.is_cof request_dict["num"] = profile.num - profile_form = RegistrationProfileForm(request_dict, instance=profile) + profile_form = RegistrationProfileForm(request_dict, + instance=profile) profile_form.is_valid() profile_form.save() (profile, _) = CofProfile.objects.get_or_create(user=member) @@ -390,26 +443,39 @@ def registration(request): for form in event_forms: if form.cleaned_data['status'] == 'no': try: - current_registration = EventRegistration.objects.get(user=member, event=form.event) + current_registration = EventRegistration.objects.get( + user=member, event=form.event) current_registration.delete() except EventRegistration.DoesNotExist: pass continue all_choices = get_event_form_choices(form.event, form) - (current_registration, created_reg) = EventRegistration.objects.get_or_create(user=member, event=form.event) + (current_registration, created_reg) = \ + EventRegistration.objects.get_or_create(user=member, + event=form.event) update_event_form_comments(event, form, current_registration) current_registration.options = all_choices - current_registration.paid = (form.cleaned_data['status'] == 'paid') + current_registration.paid = \ + (form.cleaned_data['status'] == 'paid') current_registration.save() if event.title == "Mega 15" and created_reg: - field = EventCommentField.objects.get(event=event, name="Commentaires") + field = EventCommentField.objects.get(event=event, + name="Commentaires") try: - comments = EventCommentValue.objects.get(commentfield=field, registration=current_registration).content + comments = EventCommentValue.objects.get( + commentfield=field, + registration=current_registration).content except EventCommentValue.DoesNotExist: comments = field.default send_custom_mail(member, "mega", {"remarques": comments}) success = True - return render(request, "registration_post.html", {"success": success, "user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper, "event_forms": event_forms}) + return render(request, "registration_post.html", + {"success": success, + "user_form": user_form, + "profile_form": profile_form, + "member": member, + "login_clipper": login_clipper, + "event_forms": event_forms}) else: return render(request, "registration.html") @@ -422,7 +488,9 @@ def export_members(request): writer = unicodecsv.writer(response) for profile in CofProfile.objects.filter(is_cof=True).all(): user = profile.user - bits = [profile.num, user.username, user.first_name, user.last_name, user.email, profile.phone, profile.occupation, profile.departement, profile.type_cotiz] + bits = [profile.num, user.username, user.first_name, user.last_name, + user.email, profile.phone, profile.occupation, + profile.departement, profile.type_cotiz] writer.writerow([unicode(bit) for bit in bits]) return response @@ -437,8 +505,12 @@ def csv_export_mega(filename, qs): for reg in qs.all(): user = reg.user profile = user.profile - comments = "---".join([comment.content for comment in reg.comments.all()]) - bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments if profile.comments else "", comments] + comments = "---".join( + [comment.content for comment in reg.comments.all()]) + bits = [user.username, user.first_name, user.last_name, user.email, + profile.phone, profile.num, + profile.comments if profile.comments else "", comments] + writer.writerow([unicode(bit) for bit in bits]) return response @@ -457,7 +529,8 @@ def export_mega_remarksonly(request): reg = val.registration user = reg.user profile = user.profile - bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments, val.content] + bits = [user.username, user.first_name, user.last_name, user.email, + profile.phone, profile.num, profile.comments, val.content] writer.writerow([unicode(bit) for bit in bits]) return response @@ -476,7 +549,8 @@ def export_mega_bytype(request, type): event = Event.objects.get(title="Mega 15") type_option = event.options.get(name="Type") participant_type = type_option.choices.get(value=types[type]).id - qs = EventRegistration.objects.filter(event=event).filter(options__id__exact=participant_type) + qs = EventRegistration.objects.filter(event=event).filter( + options__id__exact=participant_type) return csv_export_mega(type + '_mega_2015.csv', qs) @@ -486,7 +560,8 @@ def export_mega_orgas(request): type_option = event.options.get(name="Type") participant_type_a = type_option.choices.get(value="Conscrit étudiant").id participant_type_b = type_option.choices.get(value="Conscrit élève").id - qs = EventRegistration.objects.filter(event=event).exclude(options__id__in=(participant_type_a, participant_type_b)) + qs = EventRegistration.objects.filter(event=event).exclude( + options__id__in=(participant_type_a, participant_type_b)) return csv_export_mega('orgas_mega_15.csv', qs) @@ -496,14 +571,16 @@ def export_mega_participants(request): type_option = event.options.get(name="Type") participant_type_a = type_option.choices.get(value="Conscrit étudiant").id participant_type_b = type_option.choices.get(value="Conscrit élève").id - qs = EventRegistration.objects.filter(event=event).filter(options__id__in=(participant_type_a, participant_type_b)) + qs = EventRegistration.objects.filter(event=event).filter( + options__id__in=(participant_type_a, participant_type_b)) return csv_export_mega('participants_mega_15.csv', qs) @buro_required def export_mega(request): event = Event.objects.filter(title="Mega 15") - qs = EventRegistration.objects.filter(event=event).order_by("user__username") + qs = EventRegistration.objects.filter(event=event).\ + order_by("user__username") return csv_export_mega('all_mega_2015.csv', qs) @@ -522,18 +599,22 @@ def utile_bda(request): def liste_bdadiff(request): titre = "BdA diffusion" personnes = CofProfile.objects.filter(mailing_bda=True, is_cof=True).all() - return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes}) + return render(request, "liste_mails.html", + {"titre": titre, "personnes": personnes}) @buro_required def liste_bdarevente(request): titre = "BdA revente" - personnes = CofProfile.objects.filter(mailing_bda_revente=True, is_cof=True).all() - return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes}) + personnes = CofProfile.objects.filter(mailing_bda_revente=True, + is_cof=True).all() + return render(request, "liste_mails.html", {"titre": titre, + "personnes": personnes}) @buro_required def liste_diffcof(request): titre = "Diffusion COF" personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all() - return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes}) + return render(request, "liste_mails.html", {"titre": titre, + "personnes": personnes}) diff --git a/gestioncof/widgets.py b/gestioncof/widgets.py index 4c864e38..0f36f202 100644 --- a/gestioncof/widgets.py +++ b/gestioncof/widgets.py @@ -2,8 +2,8 @@ from django.forms.widgets import Widget from django.forms.utils import flatatt from django.utils.safestring import mark_safe -class TriStateCheckbox(Widget): +class TriStateCheckbox(Widget): def __init__(self, attrs=None, choices=()): super(TriStateCheckbox, self).__init__(attrs) # choices can be any iterable, but we may need to render this widget @@ -12,7 +12,8 @@ class TriStateCheckbox(Widget): self.choices = list(choices) def render(self, name, value, attrs=None, choices=()): - if value is None: value = 'none' + if value is None: + value = 'none' final_attrs = self.build_attrs(attrs, value=value) output = [u"" % flatatt(final_attrs)] return mark_safe('\n'.join(output)) diff --git a/tirage_bda.py b/tirage_bda.py index bd021784..a4e46380 100644 --- a/tirage_bda.py +++ b/tirage_bda.py @@ -15,16 +15,19 @@ if __name__ == "__main__": start = time.time() shows = Spectacle.objects.all() members = Participant.objects.all() - choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all() + choices = ChoixSpectacle.objects.order_by('participant', 'priority').\ + select_related().all() available_slots = Spectacle.objects.aggregate(Sum('slots'))['slots__sum'] cursor = connection.cursor() - cursor.execute("SELECT SUM(`slots` * `price`) AS `total` FROM `bda_spectacle`;") + cursor.execute( + "SELECT SUM(`slots` * `price`) AS `total` FROM `bda_spectacle`;") total_price = cursor.fetchone()[0] print "%d spectacles" % len(shows) print "%d places" % available_slots print "%d participants" % len(members) print "%d demandes" % len(choices) - print "%d places demandées" % (len(choices) + len(choices.filter(double=True).all())) + print "%d places demandées" % (len(choices) + + len(choices.filter(double=True).all())) print "%.02f€ à brasser" % total_price print "Récupération: %.2fs" % (time.time() - start) start_init = time.time() @@ -54,7 +57,8 @@ if __name__ == "__main__": members2[member].append(show) member.total += show.price if len(members) < show.slots: - print "%d place(s) invendue(s) pour %s" % (show.slots - len(members), show) + print "%d place(s) invendue(s) pour %s" %\ + (show.slots - len(members), show) members2 = members2.items() print "Temps total: %.2fs" % (time.time() - start) print "Requêtes SQL:"