PEP8: Enforced other rules, including 80 cols

This commit is contained in:
Théophile Bastian 2016-07-09 21:31:56 +01:00
parent c7a3656ded
commit 88bccc0e60
23 changed files with 571 additions and 324 deletions

View file

@ -6,7 +6,7 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
""" """
import os import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings")
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings")
application = get_wsgi_application() application = get_wsgi_application()

View file

@ -4,27 +4,36 @@ from django.core.mail import send_mail
from django.contrib import admin from django.contrib import admin
from django.db.models import Sum, Count 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 django import forms
from datetime import timedelta from datetime import timedelta
import autocomplete_light
class ChoixSpectacleInline(admin.TabularInline): class ChoixSpectacleInline(admin.TabularInline):
model = ChoixSpectacle model = ChoixSpectacle
sortable_field_name = "priority" sortable_field_name = "priority"
class AttributionInline(admin.TabularInline): class AttributionInline(admin.TabularInline):
model = Attribution model = Attribution
class ParticipantAdmin(admin.ModelAdmin): class ParticipantAdmin(admin.ModelAdmin):
inlines = [AttributionInline] inlines = [AttributionInline]
def get_queryset(self, request): def get_queryset(self, request):
return Participant.objects.annotate(nb_places=Count('attributions'), return Participant.objects.annotate(nb_places=Count('attributions'),
total=Sum('attributions__price')) total=Sum('attributions__price'))
def nb_places(self, obj): def nb_places(self, obj):
return obj.nb_places return obj.nb_places
nb_places.admin_order_field = "nb_places" nb_places.admin_order_field = "nb_places"
nb_places.short_description = "Nombre de places" nb_places.short_description = "Nombre de places"
def total(self, obj): def total(self, obj):
tot = obj.total tot = obj.total
if tot: 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 Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as
obtenu aucune place. obtenu aucune place.
Nous proposons cependant de nombreuses offres hors-tirage tout au long de 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 ! l'année, et nous t'invitons à nous contacter si l'une d'entre elles
t'intéresse !
-- --
Le Bureau des Arts 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 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 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 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 évidemment possibles : nous pouvons ne pas encaisser le chèque immédiatement,
bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas venir ou bien découper votre paiement en deux fois. Pour ceux qui ne pourraient pas
payer au bureau, merci de nous contacter par mail. venir payer au bureau, merci de nous contacter par mail.
*Mode de retrait des places* *Mode de retrait des places*
Au moment du paiement, certaines places vous seront remises directement, d'autres Au moment du paiement, certaines places vous seront remises directement,
seront à récupérer au cours de l'année, d'autres encore seront nominatives et à retirer d'autres seront à récupérer au cours de l'année, d'autres encore seront
le soir même dans les theâtres correspondants. Pour chaque spectacle, vous recevrez un mail nominatives et à retirer le soir même dans les theâtres correspondants.
quelques jours avant la représentation vous indiquant le mode de retrait. 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 à Nous vous rappelons que l'obtention de places du BdA vous engage à
respecter les règles de fonctionnement : respecter les règles de fonctionnement :
@ -96,10 +107,11 @@ Le Bureau des Arts
for attrib in attribs: for attrib in attribs:
attribs_text += u"- 1 place pour %s\n" % attrib attribs_text += u"- 1 place pour %s\n" % attrib
deadline = member.tirage.fermeture + timedelta(days=7) deadline = member.tirage.fermeture + timedelta(days=7)
mail = mail % (name, attribs_text, deadline.strftime('%d %b %Y')) mail = mail % (name, attribs_text,
send_mail ("Résultats du tirage au sort", mail, deadline.strftime('%d %b %Y'))
"bda@ens.fr", [member.user.email], send_mail("Résultats du tirage au sort", mail,
fail_silently=True) "bda@ens.fr", [member.user.email],
fail_silently=True)
count = len(queryset.all()) count = len(queryset.all())
if count == 1: if count == 1:
message_bit = u"1 membre a" message_bit = u"1 membre a"
@ -107,9 +119,11 @@ Le Bureau des Arts
else: else:
message_bit = u"%d membres ont" % count message_bit = u"%d membres ont" % count
plural = "s" 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" send_attribs.short_description = u"Envoyer les résultats par mail"
class AttributionAdminForm(forms.ModelForm): class AttributionAdminForm(forms.ModelForm):
def clean(self): def clean(self):
cleaned_data = super(AttributionAdminForm, self).clean() cleaned_data = super(AttributionAdminForm, self).clean()
@ -117,26 +131,36 @@ class AttributionAdminForm(forms.ModelForm):
spectacle = cleaned_data.get("spectacle") spectacle = cleaned_data.get("spectacle")
if participant and spectacle: if participant and spectacle:
if participant.tirage != spectacle.tirage: 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 return cleaned_data
class AttributionAdmin(admin.ModelAdmin): class AttributionAdmin(admin.ModelAdmin):
def paid(self, obj): def paid(self, obj):
return obj.participant.paid return obj.participant.paid
paid.short_description = 'A payé' paid.short_description = 'A payé'
paid.boolean = True paid.boolean = True
list_display = ("id", "spectacle", "participant", "given", "paid") 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 form = AttributionAdminForm
import autocomplete_light
class ChoixSpectacleAdmin(admin.ModelAdmin): class ChoixSpectacleAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[]) form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[])
def tirage(self, obj): def tirage(self, obj):
return obj.participant.tirage 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") 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): class SpectacleAdmin(admin.ModelAdmin):
model = Spectacle model = Spectacle
@ -144,6 +168,7 @@ class SpectacleAdmin(admin.ModelAdmin):
list_filter = ("location", "tirage",) list_filter = ("location", "tirage",)
search_fields = ("title", "location__name") search_fields = ("title", "location__name")
class TirageAdmin(admin.ModelAdmin): class TirageAdmin(admin.ModelAdmin):
model = Tirage model = Tirage
list_display = ("title", "ouverture", "fermeture", "active") list_display = ("title", "ouverture", "fermeture", "active")

View file

@ -6,6 +6,7 @@ from django.db.models import Max
import random import random
class Algorithm(object): class Algorithm(object):
shows = None shows = None
@ -19,7 +20,8 @@ class Algorithm(object):
show.requests show.requests
- on crée des tables de demandes pour chaque personne, afin de - on crée des tables de demandes pour chaque personne, afin de
pouvoir modifier les rankings""" 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 = [] self.shows = []
showdict = {} showdict = {}
for show in shows: for show in shows:
@ -65,13 +67,14 @@ class Algorithm(object):
def __call__(self, seed): def __call__(self, seed):
random.seed(seed) random.seed(seed)
results = [] 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: for show in shows:
# On regroupe tous les gens ayant le même rang # On regroupe tous les gens ayant le même rang
groups = dict([(i, []) for i in range(1, self.max_group + 1)]) groups = dict([(i, []) for i in range(1, self.max_group + 1)])
for member in show.requests: for member in show.requests:
if self.ranks[member][show] == 0: if self.ranks[member][show] == 0:
raise RuntimeError, (member, show.title) raise RuntimeError(member, show.title)
groups[self.ranks[member][show]].append(member) groups[self.ranks[member][show]].append(member)
# On passe à l'attribution # On passe à l'attribution
winners = [] winners = []
@ -84,7 +87,8 @@ class Algorithm(object):
if len(winners) + 1 < show.slots: if len(winners) + 1 < show.slots:
self.appendResult(winners, member, show) self.appendResult(winners, member, show)
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(winners, member, show)
self.appendResult(losers, member, show) self.appendResult(losers, member, show)
else: else:

View file

@ -2,8 +2,11 @@ import autocomplete_light
from bda.models import Participant, Spectacle 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_js_attributes={'placeholder': 'participant...'})
autocomplete_light.register(Spectacle, search_fields=('title',), autocomplete_light.register(
Spectacle, search_fields=('title', ),
autocomplete_js_attributes={'placeholder': 'spectacle...'}) autocomplete_js_attributes={'placeholder': 'spectacle...'})

View file

@ -4,6 +4,7 @@ from django import forms
from django.forms.models import BaseInlineFormSet from django.forms.models import BaseInlineFormSet
from bda.models import Spectacle from bda.models import Spectacle
class BaseBdaFormSet(BaseInlineFormSet): class BaseBdaFormSet(BaseInlineFormSet):
def clean(self): def clean(self):
"""Checks that no two articles have the same title.""" """Checks that no two articles have the same title."""
@ -20,22 +21,27 @@ class BaseBdaFormSet(BaseInlineFormSet):
spectacle = form.cleaned_data['spectacle'] spectacle = form.cleaned_data['spectacle']
delete = form.cleaned_data['DELETE'] delete = form.cleaned_data['DELETE']
if not delete and spectacle in spectacles: if not delete and spectacle in spectacles:
raise forms.ValidationError("Vous ne pouvez pas vous " + \ raise forms.ValidationError(
"inscrire deux fois pour le même spectacle.") "Vous ne pouvez pas vous inscrire deux fois pour le "
"même spectacle.")
spectacles.append(spectacle) spectacles.append(spectacle)
class TokenForm(forms.Form): class TokenForm(forms.Form):
token = forms.CharField(widget=forms.widgets.Textarea()) token = forms.CharField(widget=forms.widgets.Textarea())
class SpectacleModelChoiceField(forms.ModelChoiceField): class SpectacleModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj): def label_from_instance(self, obj):
return u"%s le %s (%s) à %.02f" % (obj.title, obj.date_no_seconds(), return u"%s le %s (%s) à %.02f" % (obj.title, obj.date_no_seconds(),
obj.location, obj.price) obj.location, obj.price)
class ResellForm(forms.Form): class ResellForm(forms.Form):
count = forms.ChoiceField(choices=(("1", "1"), ("2", "2"),)) 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): def __init__(self, participant, *args, **kwargs):
super(ResellForm, self).__init__(*args, **kwargs) super(ResellForm, self).__init__(*args, **kwargs)
self.fields['spectacle'].queryset = participant.attributions.all().distinct() self.fields['spectacle'].queryset = participant.attributions.all().\
distinct()

View file

@ -6,6 +6,7 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
class Tirage(models.Model): class Tirage(models.Model):
title = models.CharField("Titre", max_length=300) title = models.CharField("Titre", max_length=300)
ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") ouverture = models.DateTimeField("Date et heure d'ouverture du tirage")
@ -19,6 +20,7 @@ class Tirage(models.Model):
def __unicode__(self): def __unicode__(self):
return u"%s - %s" % (self.title, self.date_no_seconds()) return u"%s - %s" % (self.title, self.date_no_seconds())
class Salle(models.Model): class Salle(models.Model):
name = models.CharField("Nom", max_length=300) name = models.CharField("Nom", max_length=300)
address = models.TextField("Adresse") address = models.TextField("Adresse")
@ -26,6 +28,7 @@ class Salle(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class Spectacle(models.Model): class Spectacle(models.Model):
title = models.CharField("Titre", max_length=300) title = models.CharField("Titre", max_length=300)
date = models.DateTimeField("Date & heure") date = models.DateTimeField("Date & heure")
@ -52,7 +55,7 @@ class Spectacle(models.Model):
def __unicode__(self): def __unicode__(self):
return u"%s - %s, %s, %.02f" % (self.title, self.date_no_seconds(), return u"%s - %s, %s, %.02f" % (self.title, self.date_no_seconds(),
self.location, self.price) self.location, self.price)
PAYMENT_TYPES = ( PAYMENT_TYPES = (
("cash", u"Cash"), ("cash", u"Cash"),
@ -61,17 +64,19 @@ PAYMENT_TYPES = (
("autre", u"Autre"), ("autre", u"Autre"),
) )
class Participant(models.Model): class Participant(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
choices = models.ManyToManyField(Spectacle, choices = models.ManyToManyField(Spectacle,
through="ChoixSpectacle", through="ChoixSpectacle",
related_name="chosen_by") related_name="chosen_by")
attributions = models.ManyToManyField(Spectacle, attributions = models.ManyToManyField(Spectacle,
through="Attribution", through="Attribution",
related_name="attributed_to") related_name="attributed_to")
paid = models.BooleanField(u"A payé", default=False) paid = models.BooleanField(u"A payé", default=False)
paymenttype = models.CharField(u"Moyen de paiement", 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) tirage = models.ForeignKey(Tirage)
def __unicode__(self): def __unicode__(self):
@ -83,12 +88,14 @@ DOUBLE_CHOICES = (
("double", "2 places sinon rien"), ("double", "2 places sinon rien"),
) )
class ChoixSpectacle(models.Model): class ChoixSpectacle(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(Participant)
spectacle = models.ForeignKey(Spectacle, related_name="participants") spectacle = models.ForeignKey(Spectacle, related_name="participants")
priority = models.PositiveIntegerField("Priorité") priority = models.PositiveIntegerField("Priorité")
double_choice = models.CharField("Nombre de places", 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): def get_double(self):
return self.double_choice != "1" return self.double_choice != "1"
@ -104,6 +111,7 @@ class ChoixSpectacle(models.Model):
verbose_name = "voeu" verbose_name = "voeu"
verbose_name_plural = "voeux" verbose_name_plural = "voeux"
class Attribution(models.Model): class Attribution(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(Participant)
spectacle = models.ForeignKey(Spectacle, related_name="attribues") spectacle = models.ForeignKey(Spectacle, related_name="attribues")

View file

@ -3,7 +3,8 @@
from django.conf.urls import url, patterns from django.conf.urls import url, patterns
from bda.views import SpectacleListView from bda.views import SpectacleListView
urlpatterns = patterns('', urlpatterns = patterns(
'',
url(r'inscription/(?P<tirage_id>\d+)$', url(r'inscription/(?P<tirage_id>\d+)$',
'bda.views.inscription', 'bda.views.inscription',
name='bda-tirage-inscription'), name='bda-tirage-inscription'),

View file

@ -18,7 +18,8 @@ from datetime import timedelta
import time import time
from gestioncof.decorators import cof_required, buro_required 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.algorithm import Algorithm
from bda.forms import BaseBdaFormSet, TokenForm, ResellForm from bda.forms import BaseBdaFormSet, TokenForm, ResellForm
@ -59,7 +60,7 @@ def etat_places(request, tirage_id):
spectacles_dict[spectacle["spectacle"]].slots spectacles_dict[spectacle["spectacle"]].slots
total += spectacle["total"] total += spectacle["total"]
return render(request, "etat-places.html", return render(request, "etat-places.html",
{"spectacles": spectacles, "total": total, 'tirage': tirage}) {"spectacles": spectacles, "total": total, 'tirage': tirage})
def _hash_queryset(queryset): def _hash_queryset(queryset):
@ -73,9 +74,9 @@ def _hash_queryset(queryset):
def places(request, tirage_id): def places(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
participant, created = Participant.objects.get_or_create( participant, created = Participant.objects.get_or_create(
user=request.user, tirage=tirage) user=request.user, tirage=tirage)
places = participant.attribution_set.order_by( places = participant.attribution_set.order_by(
"spectacle__date", "spectacle").all() "spectacle__date", "spectacle").all()
total = sum([place.spectacle.price for place in places]) total = sum([place.spectacle.price for place in places])
filtered_places = [] filtered_places = []
places_dict = {} places_dict = {}
@ -107,9 +108,9 @@ def places(request, tirage_id):
def places_ics(request, tirage_id): def places_ics(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
participant, created = Participant.objects.get_or_create( participant, created = Participant.objects.get_or_create(
user=request.user, tirage=tirage) user=request.user, tirage=tirage)
places = participant.attribution_set.order_by( places = participant.attribution_set.order_by(
"spectacle__date", "spectacle").all() "spectacle__date", "spectacle").all()
filtered_places = [] filtered_places = []
places_dict = {} places_dict = {}
spectacles = [] spectacles = []
@ -133,30 +134,32 @@ def inscription(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
if timezone.now() < tirage.ouverture: if timezone.now() < tirage.ouverture:
error_desc = "Ouverture le %s" % ( 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', return render(request, 'resume_inscription.html',
{ "error_title": "Le tirage n'est pas encore ouvert !", {"error_title": "Le tirage n'est pas encore ouvert !",
"error_description": error_desc}) "error_description": error_desc})
if timezone.now() > tirage.fermeture: if timezone.now() > tirage.fermeture:
participant, created = Participant.objects.get_or_create( 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() choices = participant.choixspectacle_set.order_by("priority").all()
return render(request, "resume_inscription.html", return render(request, "resume_inscription.html",
{ "error_title": "C'est fini !", {"error_title": "C'est fini !",
"error_description": u"Tirage au sort dans la journée !", "error_description":
"choices": choices}) u"Tirage au sort dans la journée !",
"choices": choices})
def formfield_callback(f, **kwargs): def formfield_callback(f, **kwargs):
if f.name == "spectacle": if f.name == "spectacle":
kwargs['queryset'] = tirage.spectacle_set kwargs['queryset'] = tirage.spectacle_set
return f.formfield(**kwargs) return f.formfield(**kwargs)
BdaFormSet = inlineformset_factory( BdaFormSet = inlineformset_factory(
Participant, Participant,
ChoixSpectacle, ChoixSpectacle,
fields=("spectacle", "double_choice", "priority"), fields=("spectacle", "double_choice", "priority"),
formset=BaseBdaFormSet, formset=BaseBdaFormSet,
formfield_callback=formfield_callback) formfield_callback=formfield_callback)
participant, created = Participant.objects.get_or_create( participant, created = Participant.objects.get_or_create(
user=request.user, tirage=tirage) user=request.user, tirage=tirage)
success = False success = False
stateerror = False stateerror = False
if request.method == "POST": if request.method == "POST":
@ -179,12 +182,12 @@ def inscription(request, tirage_id):
if choice.double: if choice.double:
total_price += choice.spectacle.price total_price += choice.spectacle.price
return render(request, "inscription-bda.html", return render(request, "inscription-bda.html",
{ "formset": formset, {"formset": formset,
"success": success, "success": success,
"total_price": total_price, "total_price": total_price,
"dbstate": dbstate, "dbstate": dbstate,
'tirage': tirage, 'tirage': tirage,
"stateerror": stateerror}) "stateerror": stateerror})
def do_tirage(request, tirage_id): def do_tirage(request, tirage_id):
@ -198,8 +201,8 @@ def do_tirage(request, tirage_id):
data = {} data = {}
shows = tirage_elt.spectacle_set.select_related().all() shows = tirage_elt.spectacle_set.select_related().all()
members = tirage_elt.participant_set.all() members = tirage_elt.participant_set.all()
choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt).order_by( choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage_elt).\
'participant', 'priority').select_related().all() order_by('participant', 'priority').select_related().all()
algo = Algorithm(shows, members, choices) algo = Algorithm(shows, members, choices)
results = algo(form.cleaned_data["token"]) results = algo(form.cleaned_data["token"])
total_slots = 0 total_slots = 0
@ -248,8 +251,8 @@ def do_tirage(request, tirage_id):
# cf. issue #32 # cf. issue #32
if False: if False:
Attribution.objects.filter( Attribution.objects.filter(
spectacle__tirage=tirage_elt spectacle__tirage=tirage_elt
).delete() ).delete()
for (show, members, _) in results: for (show, members, _) in results:
for (member, _, _, _) in members: for (member, _, _, _) in members:
attrib = Attribution(spectacle=show, participant=member) 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 ! Contactez moi par email si vous êtes intéressé·e·s !
%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), %s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(),
spectacle.location, spectacle.price, request.user.get_full_name(), spectacle.location, spectacle.price,
request.user.email) request.user.get_full_name(), request.user.email)
send_mail("%s" % spectacle, mail, send_mail("%s" % spectacle, mail,
request.user.email, ["bda-revente@lists.ens.fr"], request.user.email, ["bda-revente@lists.ens.fr"],
fail_silently=False) 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 @login_required
def revente(request, tirage_id): def revente(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
participant, created = Participant.objects.get_or_create( participant, created = Participant.objects.get_or_create(
user=request.user, tirage=tirage) user=request.user, tirage=tirage)
if not participant.paid: if not participant.paid:
return render(request, "bda-notpaid.html", {}) return render(request, "bda-notpaid.html", {})
if request.POST: if request.POST:
@ -301,7 +305,8 @@ def revente(request, tirage_id):
return do_resell(request, form) return do_resell(request, form)
else: else:
form = ResellForm(participant) 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 @buro_required
@ -326,9 +331,9 @@ def spectacle(request, tirage_id, spectacle_id):
participants[participant.id] = participant_info participants[participant.id] = participant_info
participants_info = sorted(participants.values(), participants_info = sorted(participants.values(),
key=lambda part: part['lastname']) key=lambda part: part['lastname'])
return render(request, "bda-participants.html", return render(request, "bda-participants.html",
{"spectacle": spectacle, "participants": participants_info}) {"spectacle": spectacle, "participants": participants_info})
class SpectacleListView(ListView): class SpectacleListView(ListView):
@ -351,8 +356,8 @@ class SpectacleListView(ListView):
def unpaid(request, tirage_id): def unpaid(request, tirage_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
unpaid = tirage.participant_set \ unpaid = tirage.participant_set \
.annotate(nb_attributions=Count('attribution')) \ .annotate(nb_attributions=Count('attribution')) \
.filter(paid=False, nb_attributions__gt=0).all() .filter(paid=False, nb_attributions__gt=0).all()
return render(request, "bda-unpaid.html", {"unpaid": unpaid}) return render(request, "bda-unpaid.html", {"unpaid": unpaid})
@ -363,5 +368,5 @@ def liste_spectacles_ics(request, tirage_id):
for spectacle in spectacles: for spectacle in spectacles:
spectacle.dtend = spectacle.date + timedelta(seconds=7200) spectacle.dtend = spectacle.date + timedelta(seconds=7200)
return render(request, "liste_spectacles.ics", return render(request, "liste_spectacles.ics",
{"spectacles": spectacles, "tirage": tirage}, {"spectacles": spectacles, "tirage": tirage},
content_type="text/calendar") content_type="text/calendar")

View file

@ -148,11 +148,14 @@ RECAPTCHA_PUBLIC_KEY = "DUMMY"
RECAPTCHA_PRIVATE_KEY = "DUMMY" RECAPTCHA_PRIVATE_KEY = "DUMMY"
RECAPTCHA_USE_SSL = True 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): 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: if not DEBUG:
return False return False
if request.is_ajax(): if request.is_ajax():

View file

@ -12,7 +12,8 @@ from gestioncof.urls import export_patterns, petitcours_patterns, \
autocomplete_light.autodiscover() autocomplete_light.autodiscover()
admin.autodiscover() admin.autodiscover()
urlpatterns = patterns('', urlpatterns = patterns(
'',
# Page d'accueil # Page d'accueil
url(r'^$', 'gestioncof.views.home', name='home'), url(r'^$', 'gestioncof.views.home', name='home'),
# Le BdA # Le BdA
@ -27,38 +28,39 @@ urlpatterns = patterns('',
url(r'^event/', include(events_patterns)), url(r'^event/', include(events_patterns)),
# Authentification # Authentification
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'), 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/login$', 'django_cas_ng.views.login', name="cas_login_view"),
url(r'^cas/logout$', 'django_cas_ng.views.logout'), url(r'^cas/logout$', 'django_cas_ng.views.logout'),
url(r'^outsider/login$', 'gestioncof.views.login_ext'), url(r'^outsider/login$', 'gestioncof.views.login_ext'),
url(r'^outsider/logout$', 'django.contrib.auth.views.logout', url(r'^outsider/logout$', 'django.contrib.auth.views.logout',
{'next_page': 'home'}), {'next_page': 'home'}),
url(r'^login$', 'gestioncof.views.login'), url(r'^login$', 'gestioncof.views.login'),
url(r'^logout$', 'gestioncof.views.logout'), url(r'^logout$', 'gestioncof.views.logout'),
# Infos persos # Infos persos
url(r'^profile$', 'gestioncof.views.profile'), url(r'^profile$', 'gestioncof.views.profile'),
url(r'^outsider/password-change$', url(r'^outsider/password-change$',
'django.contrib.auth.views.password_change'), 'django.contrib.auth.views.password_change'),
url(r'^outsider/password-change-done$', url(r'^outsider/password-change-done$',
'django.contrib.auth.views.password_change_done', 'django.contrib.auth.views.password_change_done',
name='password_change_done'), name='password_change_done'),
# Inscription d'un nouveau membre # Inscription d'un nouveau membre
url(r'^registration$', 'gestioncof.views.registration'), url(r'^registration$', 'gestioncof.views.registration'),
url(r'^registration/clipper/(?P<login_clipper>[\w-]+)$', url(r'^registration/clipper/(?P<login_clipper>[\w-]+)$',
'gestioncof.views.registration_form2', name="clipper-registration"), 'gestioncof.views.registration_form2', name="clipper-registration"),
url(r'^registration/user/(?P<username>.+)$', url(r'^registration/user/(?P<username>.+)$',
'gestioncof.views.registration_form2', name="user-registration"), 'gestioncof.views.registration_form2', name="user-registration"),
url(r'^registration/empty$', 'gestioncof.views.registration_form2', url(r'^registration/empty$', 'gestioncof.views.registration_form2',
name="empty-registration"), name="empty-registration"),
# Autocompletion # Autocompletion
url(r'^autocomplete/registration$', 'gestioncof.autocomplete.autocomplete'), url(r'^autocomplete/registration$',
'gestioncof.autocomplete.autocomplete'),
url(r'^autocomplete/', include('autocomplete_light.urls')), url(r'^autocomplete/', include('autocomplete_light.urls')),
# Interface admin # Interface admin
url(r'^admin/logout/', 'gestioncof.views.logout'), url(r'^admin/logout/', 'gestioncof.views.logout'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/(?P<app_label>[\d\w]+)/(?P<model_name>[\d\w]+)/csv/', url(r'^admin/(?P<app_label>[\d\w]+)/(?P<model_name>[\d\w]+)/csv/',
'gestioncof.csv_views.admin_list_export', 'gestioncof.csv_views.admin_list_export',
{'fields': ['username', ]}), {'fields': ['username', ]}),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
url(r'^grappelli/', include('grappelli.urls')), url(r'^grappelli/', include('grappelli.urls')),
# Liens utiles du COF et du BdA # Liens utiles du COF et du BdA

View file

@ -9,8 +9,11 @@ from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ 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): def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower() 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: if not link_obj.id:
return "" return ""
url = reverse(reverse_path, args=(link_obj.id,)) url = reverse(reverse_path, args=(link_obj.id,))
return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj))) return mark_safe("<a href='%s'>%s</a>" %
(url, link_text(link_obj)))
link.allow_tags = True link.allow_tags = True
link.short_description = desc_text(reverse_name + ' link') link.short_description = desc_text(reverse_name + ' link')
cls.link = 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 cls
return add_link return add_link
@ -42,14 +47,14 @@ class SurveyQuestionInline(admin.TabularInline):
class SurveyQuestionAdmin(admin.ModelAdmin): class SurveyQuestionAdmin(admin.ModelAdmin):
inlines = [ inlines = [
SurveyQuestionAnswerInline, SurveyQuestionAnswerInline,
] ]
class SurveyAdmin(admin.ModelAdmin): class SurveyAdmin(admin.ModelAdmin):
inlines = [ inlines = [
SurveyQuestionInline, SurveyQuestionInline,
] ]
class EventOptionChoiceInline(admin.TabularInline): class EventOptionChoiceInline(admin.TabularInline):
@ -68,15 +73,15 @@ class EventCommentFieldInline(admin.TabularInline):
class EventOptionAdmin(admin.ModelAdmin): class EventOptionAdmin(admin.ModelAdmin):
inlines = [ inlines = [
EventOptionChoiceInline, EventOptionChoiceInline,
] ]
class EventAdmin(admin.ModelAdmin): class EventAdmin(admin.ModelAdmin):
inlines = [ inlines = [
EventOptionInline, EventOptionInline,
EventCommentFieldInline, EventCommentFieldInline,
] ]
class CofProfileInline(admin.StackedInline): class CofProfileInline(admin.StackedInline):
@ -85,7 +90,8 @@ class CofProfileInline(admin.StackedInline):
class FkeyLookup(object): 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.fk, fkattrs = fkeydecl.split('__', 1)
self.fkattrs = fkattrs.split('__') self.fkattrs = fkattrs.split('__')
@ -94,9 +100,12 @@ class FkeyLookup(object):
def __get__(self, obj, klass): def __get__(self, obj, klass):
if obj is None: 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
# <wink>) None, then we're a class, and classes are callable
<wink>)
"""
return self
item = getattr(obj, self.fk) item = getattr(obj, self.fk)
for attr in self.fkattrs: for attr in self.fkattrs:
item = getattr(item, attr) item = getattr(item, attr)
@ -113,14 +122,16 @@ def ProfileInfo(field, short_description, boolean=False):
getter.boolean = boolean getter.boolean = boolean
return getter 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_num = FkeyLookup("profile__num", "Numéro")
User.profile_phone = ProfileInfo("phone", "Téléphone") User.profile_phone = ProfileInfo("phone", "Téléphone")
User.profile_occupation = ProfileInfo("occupation", "Occupation") User.profile_occupation = ProfileInfo("occupation", "Occupation")
User.profile_departement = ProfileInfo("departement", "Departement") User.profile_departement = ProfileInfo("departement", "Departement")
User.profile_mailing_cof = ProfileInfo("mailing_cof", "ML COF", True) User.profile_mailing_cof = ProfileInfo("mailing_cof", "ML COF", True)
User.profile_mailing_bda = ProfileInfo("mailing_bda", "ML BDA", 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): class UserProfileAdmin(UserAdmin):
@ -131,6 +142,7 @@ class UserProfileAdmin(UserAdmin):
return False return False
is_buro.short_description = 'Membre du Buro' is_buro.short_description = 'Membre du Buro'
is_buro.boolean = True is_buro.boolean = True
def is_cof(self, obj): def is_cof(self, obj):
try: try:
return obj.profile.is_cof return obj.profile.is_cof
@ -139,19 +151,18 @@ class UserProfileAdmin(UserAdmin):
is_cof.short_description = 'Membre du COF' is_cof.short_description = 'Membre du COF'
is_cof.boolean = True is_cof.boolean = True
list_display = ('profile_num',) + UserAdmin.list_display \ list_display = ('profile_num',) + UserAdmin.list_display \
+ ( 'profile_login_clipper','profile_phone','profile_occupation', + ('profile_login_clipper', 'profile_phone', 'profile_occupation',
'profile_mailing_cof','profile_mailing_bda', 'profile_mailing_cof', 'profile_mailing_bda',
'profile_mailing_bda_revente','is_cof','is_buro',) 'profile_mailing_bda_revente', 'is_cof', 'is_buro', )
list_display_links = ('username','email','first_name','last_name') list_display_links = ('username', 'email', 'first_name', 'last_name')
list_filter = UserAdmin.list_filter \ list_filter = UserAdmin.list_filter \
+ ( 'profile__is_cof', 'profile__is_buro', 'profile__mailing_cof', + ('profile__is_cof', 'profile__is_buro', 'profile__mailing_cof',
'profile__mailing_bda') 'profile__mailing_bda')
search_fields = UserAdmin.search_fields + ('profile__phone',) search_fields = UserAdmin.search_fields + ('profile__phone',)
inlines = [ inlines = [
CofProfileInline, CofProfileInline,
] ]
import autocomplete_light
def user_unicode(self): def user_unicode(self):
if self.first_name and self.last_name: if self.first_name and self.last_name:
@ -163,29 +174,29 @@ User.__unicode__ = user_unicode
class EventRegistrationAdmin(admin.ModelAdmin): class EventRegistrationAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(EventRegistration, exclude=[]) form = autocomplete_light.modelform_factory(EventRegistration, exclude=[])
list_display = ('__unicode__','event','user','paid') list_display = ('__unicode__', 'event', 'user', 'paid')
list_filter = ('paid',) list_filter = ('paid',)
search_fields = ('user__username', 'user__first_name', 'user__last_name', search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'event__title') 'user__email', 'event__title')
class PetitCoursAbilityAdmin(admin.ModelAdmin): 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', search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name', 'niveau') 'user__email', 'matiere__name', 'niveau')
list_filter = ('matiere','niveau','agrege') list_filter = ('matiere', 'niveau', 'agrege')
class PetitCoursAttributionAdmin(admin.ModelAdmin): class PetitCoursAttributionAdmin(admin.ModelAdmin):
list_display = ('user','demande','matiere','rank',) list_display = ('user', 'demande', 'matiere', 'rank', )
class PetitCoursAttributionCounterAdmin(admin.ModelAdmin): class PetitCoursAttributionCounterAdmin(admin.ModelAdmin):
list_display = ('user','matiere','count',) list_display = ('user', 'matiere', 'count', )
list_filter = ('matiere',) list_filter = ('matiere',)
search_fields = ('user__username', 'user__first_name', 'user__last_name', search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name') 'user__email', 'matiere__name')
actions = ['reset',] actions = ['reset', ]
actions_on_bottom = True actions_on_bottom = True
def reset(self, request, queryset): def reset(self, request, queryset):
@ -194,9 +205,9 @@ class PetitCoursAttributionCounterAdmin(admin.ModelAdmin):
class PetitCoursDemandeAdmin(admin.ModelAdmin): class PetitCoursDemandeAdmin(admin.ModelAdmin):
list_display = ('name','email','agrege_requis','niveau','created', list_display = ('name', 'email', 'agrege_requis', 'niveau', 'created',
'traitee','processed') 'traitee', 'processed')
list_filter = ('traitee','niveau') list_filter = ('traitee', 'niveau')
admin.site.register(Survey, SurveyAdmin) admin.site.register(Survey, SurveyAdmin)
admin.site.register(SurveyQuestion, SurveyQuestionAdmin) admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
@ -210,6 +221,7 @@ admin.site.register(CustomMail)
admin.site.register(PetitCoursSubject) admin.site.register(PetitCoursSubject)
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin) admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin) admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
admin.site.register(PetitCoursAttributionCounter, PetitCoursAttributionCounterAdmin) admin.site.register(PetitCoursAttributionCounter,
PetitCoursAttributionCounterAdmin)
admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin) admin.site.register(PetitCoursDemande, PetitCoursDemandeAdmin)
admin.site.register(EventRegistration, EventRegistrationAdmin) admin.site.register(EventRegistration, EventRegistrationAdmin)

View file

@ -35,9 +35,12 @@ def autocomplete(request):
| Q(username__icontains=bit)) | Q(username__icontains=bit))
queries['members'] = queries['members'].distinct() queries['members'] = queries['members'].distinct()
queries['users'] = queries['users'].distinct() queries['users'] = queries['users'].distinct()
usernames = list(queries['members'].values_list('login_clipper', flat='True')) \ usernames = list(queries['members'].values_list('login_clipper',
+ list(queries['users'].values_list('profile__login_clipper', flat='True')) flat='True')) \
queries['clippers'] = queries['clippers'].exclude(username__in=usernames).distinct() + list(queries['users'].values_list('profile__login_clipper',
flat='True'))
queries['clippers'] = queries['clippers'].\
exclude(username__in=usernames).distinct()
# add clippers # add clippers
data.update(queries) data.update(queries)

View file

@ -2,5 +2,6 @@ import autocomplete_light
from django.contrib.auth.models import User 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...'}) autocomplete_js_attributes={'placeholder': 'membre...'})

View file

@ -7,7 +7,8 @@ from django.apps import apps
def export(qs, fields=None): def export(qs, fields=None):
model = qs.model model = qs.model
response = HttpResponse(content_type='text/csv') 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) writer = csv.writer(response)
# Write headers to CSV file # Write headers to CSV file
if fields: if fields:
@ -31,10 +32,12 @@ def export(qs, fields=None):
return response 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 Put the following line in your urls.py BEFORE your admin include
(r'^admin/(?P<app_label>[\d\w]+)/(?P<model_name>[\d\w]+)/csv/', 'util.csv_view.admin_list_export'), (r'^admin/(?P<app_label>[\d\w]+)/(?P<model_name>[\d\w]+)/csv/',
'util.csv_view.admin_list_export'),
""" """
if not request.user.is_staff: if not request.user.is_staff:
return HttpResponseForbidden() return HttpResponseForbidden()
@ -49,12 +52,17 @@ def admin_list_export(request, model_name, app_label, queryset=None, fields=None
fields = None fields = None
return export(queryset, fields) 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 %} {% block object-tools %}
<ul class="object-tools"> <ul class="object-tools">
<li><a href="csv/{%if request.GET%}?{{request.GET.urlencode}}{%endif%}" class="addlink">Export to CSV</a></li> <li><a href="csv/{%if request.GET%}?{{request.GET.urlencode}}
{%endif%}" class="addlink">Export to CSV</a></li>
{% if has_add_permission %} {% if has_add_permission %}
<li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{ name }}{% endblocktrans %}</a></li> <li><a href="add/{% if is_popup %}?_popup=1{% endif %}"
class="addlink">
{% blocktrans with cl.opts.verbose_name|escape as name %}
Add {{ name }}{% endblocktrans %}</a></li>
{% endif %} {% endif %}
</ul> </ul>
{% endblock %} {% endblock %}

View file

@ -9,7 +9,8 @@ def is_cof(user):
return False return False
cof_required = user_passes_test(lambda u: is_cof(u)) 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): def is_buro(user):

View file

@ -26,16 +26,20 @@ class EventForm(forms.Form):
choices[choice.event_option.id].append(choice.id) choices[choice.event_option.id].append(choice.id)
all_choices = choices all_choices = choices
for option in event.options.all(): 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: if option.multi_choices:
initial = [] if option.id not in all_choices else all_choices[option.id] initial = [] if option.id not in all_choices \
field = forms.MultipleChoiceField(label=option.name, else all_choices[option.id]
choices=choices, field = forms.MultipleChoiceField(
widget=CheckboxSelectMultiple, label=option.name,
required=False, choices=choices,
initial=initial) widget=CheckboxSelectMultiple,
required=False,
initial=initial)
else: 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, field = forms.ChoiceField(label=option.name,
choices=choices, choices=choices,
widget=RadioSelect, widget=RadioSelect,
@ -63,16 +67,20 @@ class SurveyForm(forms.Form):
else: else:
answers[answer.survey_question.id].append(answer.id) answers[answer.survey_question.id].append(answer.id)
for question in survey.questions.all(): 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: if question.multi_answers:
initial = [] if question.id not in answers else answers[question.id] initial = [] if question.id not in answers\
field = forms.MultipleChoiceField(label=question.question, else answers[question.id]
choices=choices, field = forms.MultipleChoiceField(
widget=CheckboxSelectMultiple, label=question.question,
required=False, choices=choices,
initial=initial) widget=CheckboxSelectMultiple,
required=False,
initial=initial)
else: 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, field = forms.ChoiceField(label=question.question,
choices=choices, choices=choices,
widget=RadioSelect, widget=RadioSelect,
@ -94,15 +102,18 @@ class SurveyStatusFilterForm(forms.Form):
for question in survey.questions.all(): for question in survey.questions.all():
for answer in question.answers.all(): for answer in question.answers.all():
name = "question_%d_answer_%d" % (question.id, answer.id) 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) initial = self.data.get(self.add_prefix(name), None)
else: else:
initial = "none" initial = "none"
field = forms.ChoiceField(label="%s : %s" % (question.question, answer.answer), field = forms.ChoiceField(
choices=[("yes", "yes"), ("no", "no"), ("none", "none")], label="%s : %s" %
widget=TriStateCheckbox, (question.question, answer.answer),
required=False, choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
initial=initial) widget=TriStateCheckbox,
required=False,
initial=initial)
field.question_id = question.id field.question_id = question.id
field.answer_id = answer.id field.answer_id = answer.id
self.fields[name] = field self.fields[name] = field
@ -110,7 +121,8 @@ class SurveyStatusFilterForm(forms.Form):
def filters(self): def filters(self):
for name, value in self.cleaned_data.items(): for name, value in self.cleaned_data.items():
if name.startswith('question_'): 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): class EventStatusFilterForm(forms.Form):
@ -120,15 +132,17 @@ class EventStatusFilterForm(forms.Form):
for option in event.options.all(): for option in event.options.all():
for choice in option.choices.all(): for choice in option.choices.all():
name = "option_%d_choice_%d" % (option.id, choice.id) 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) initial = self.data.get(self.add_prefix(name), None)
else: else:
initial = "none" initial = "none"
field = forms.ChoiceField(label="%s : %s" % (option.name, choice.value), field = forms.ChoiceField(
choices=[("yes", "yes"), ("no", "no"), ("none", "none")], label="%s : %s" % (option.name, choice.value),
widget=TriStateCheckbox, choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
required=False, widget=TriStateCheckbox,
initial=initial) required=False,
initial=initial)
field.option_id = option.id field.option_id = option.id
field.choice_id = choice.id field.choice_id = choice.id
self.fields[name] = field self.fields[name] = field
@ -139,7 +153,8 @@ class EventStatusFilterForm(forms.Form):
else: else:
initial = "none" initial = "none"
field = forms.ChoiceField(label="Événement payé", field = forms.ChoiceField(label="Événement payé",
choices=[("yes", "yes"), ("no", "no"), ("none", "none")], choices=[("yes", "yes"), ("no", "no"),
("none", "none")],
widget=TriStateCheckbox, widget=TriStateCheckbox,
required=False, required=False,
initial=initial) initial=initial)
@ -148,7 +163,8 @@ class EventStatusFilterForm(forms.Form):
def filters(self): def filters(self):
for name, value in self.cleaned_data.items(): for name, value in self.cleaned_data.items():
if name.startswith('option_'): 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": elif name == "event_has_paid":
yield ("has_paid", None, value) yield ("has_paid", None, value)
@ -179,7 +195,8 @@ class UserProfileForm(forms.ModelForm):
class Meta: class Meta:
model = CofProfile model = CofProfile
fields = ("phone", "mailing_cof", "mailing_bda", "mailing_bda_revente", ) fields = ("phone", "mailing_cof", "mailing_bda",
"mailing_bda_revente", )
class RegistrationUserForm(forms.ModelForm): class RegistrationUserForm(forms.ModelForm):
@ -231,7 +248,9 @@ class RegistrationProfileForm(forms.ModelForm):
class Meta: class Meta:
model = CofProfile 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'), STATUS_CHOICES = (('no', 'Non'),
('wait', 'Oui mais attente paiement'), ('wait', 'Oui mais attente paiement'),
@ -239,13 +258,16 @@ STATUS_CHOICES = (('no', 'Non'),
class AdminEventForm(forms.Form): 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): def __init__(self, *args, **kwargs):
event = kwargs.pop("event") event = kwargs.pop("event")
self.event = event self.event = event
registration = kwargs.pop("current_registration", None) 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) paid = kwargs.pop("paid", None)
if paid is True: if paid is True:
kwargs["initial"] = {"status": "paid"} kwargs["initial"] = {"status": "paid"}
@ -262,16 +284,20 @@ class AdminEventForm(forms.Form):
choices[choice.event_option.id].append(choice.id) choices[choice.event_option.id].append(choice.id)
all_choices = choices all_choices = choices
for option in event.options.all(): 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: if option.multi_choices:
initial = [] if option.id not in all_choices else all_choices[option.id] initial = [] if option.id not in all_choices\
field = forms.MultipleChoiceField(label=option.name, else all_choices[option.id]
choices=choices, field = forms.MultipleChoiceField(
widget=CheckboxSelectMultiple, label=option.name,
required=False, choices=choices,
initial=initial) widget=CheckboxSelectMultiple,
required=False,
initial=initial)
else: 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, field = forms.ChoiceField(label=option.name,
choices=choices, choices=choices,
widget=RadioSelect, widget=RadioSelect,
@ -283,10 +309,12 @@ class AdminEventForm(forms.Form):
initial = commentfield.default initial = commentfield.default
if registration is not None: if registration is not None:
try: try:
initial = registration.comments.get(commentfield=commentfield).content initial = registration.comments.\
get(commentfield=commentfield).content
except EventCommentValue.DoesNotExist: except EventCommentValue.DoesNotExist:
pass 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, field = forms.CharField(label=commentfield.name,
widget=widget, widget=widget,
required=False, required=False,

View file

@ -41,21 +41,28 @@ class CofProfile(models.Model):
num = models.IntegerField("Numéro d'adhérent", blank=True, default=0) num = models.IntegerField("Numéro d'adhérent", blank=True, default=0)
phone = models.CharField("Téléphone", max_length=20, blank=True) phone = models.CharField("Téléphone", max_length=20, blank=True)
occupation = models.CharField(_(u"Occupation"), occupation = models.CharField(_(u"Occupation"),
default="1A", default="1A",
choices=OCCUPATION_CHOICES, choices=OCCUPATION_CHOICES,
max_length=choices_length(OCCUPATION_CHOICES)) max_length=choices_length(
departement = models.CharField(_(u"Département"), max_length=50, blank=True) OCCUPATION_CHOICES))
departement = models.CharField(_(u"Département"), max_length=50,
blank=True)
type_cotiz = models.CharField(_(u"Type de cotisation"), type_cotiz = models.CharField(_(u"Type de cotisation"),
default="normalien", default="normalien",
max_length=choices_length(TYPE_COTIZ_CHOICES)) max_length=choices_length(
TYPE_COTIZ_CHOICES))
mailing_cof = models.BooleanField("Recevoir les mails COF", default=False) mailing_cof = models.BooleanField("Recevoir les mails COF", default=False)
mailing_bda = models.BooleanField("Recevoir les mails BdA", 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) mailing_bda_revente = models.BooleanField(
comments = models.TextField("Commentaires visibles uniquement par le Buro", blank=True) "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) is_buro = models.BooleanField("Membre du Burô", default=False)
petits_cours_accept = models.BooleanField("Recevoir des petits cours", default=False) petits_cours_accept = models.BooleanField(
petits_cours_remarques = models.TextField(_(u"Remarques et précisions pour les petits cours"), "Recevoir des petits cours", default=False)
blank=True, default="") petits_cours_remarques = models.TextField(
_(u"Remarques et précisions pour les petits cours"),
blank=True, default="")
class Meta: class Meta:
verbose_name = "Profil COF" verbose_name = "Profil COF"
@ -82,7 +89,8 @@ class CustomMail(models.Model):
shortname = models.SlugField(max_length=50, blank=False) shortname = models.SlugField(max_length=50, blank=False)
title = models.CharField("Titre", max_length=200, blank=False) title = models.CharField("Titre", max_length=200, blank=False)
content = models.TextField("Contenu", 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: class Meta:
verbose_name = "Mails personnalisables" verbose_name = "Mails personnalisables"
@ -97,7 +105,8 @@ class Event(models.Model):
start_date = models.DateField("Date de début", blank=True, null=True) start_date = models.DateField("Date de début", blank=True, null=True)
end_date = models.DateField("Date de fin", blank=True, null=True) end_date = models.DateField("Date de fin", blank=True, null=True)
description = models.TextField("Description", blank=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) old = models.BooleanField("Archiver (événement fini)", default=False)
class Meta: class Meta:
@ -110,7 +119,8 @@ class Event(models.Model):
class EventCommentField(models.Model): class EventCommentField(models.Model):
event = models.ForeignKey(Event, related_name="commentfields") event = models.ForeignKey(Event, related_name="commentfields")
name = models.CharField("Champ", max_length=200) 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) default = models.TextField("Valeur par défaut", blank=True)
class Meta: class Meta:
@ -122,7 +132,8 @@ class EventCommentField(models.Model):
class EventCommentValue(models.Model): class EventCommentValue(models.Model):
commentfield = models.ForeignKey(EventCommentField, related_name="values") 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) content = models.TextField("Contenu", blank=True, null=True)
@ -153,7 +164,8 @@ class EventRegistration(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
event = models.ForeignKey(Event) event = models.ForeignKey(Event)
options = models.ManyToManyField(EventOptionChoice) options = models.ManyToManyField(EventOptionChoice)
filledcomments = models.ManyToManyField(EventCommentField, through=EventCommentValue) filledcomments = models.ManyToManyField(EventCommentField,
through=EventCommentValue)
paid = models.BooleanField("A payé", default=False) paid = models.BooleanField("A payé", default=False)
class Meta: class Meta:
@ -161,7 +173,8 @@ class EventRegistration(models.Model):
unique_together = ("user", "event") unique_together = ("user", "event")
def __unicode__(self): 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): class Survey(models.Model):
@ -203,7 +216,8 @@ class SurveyQuestionAnswer(models.Model):
class SurveyAnswer(models.Model): class SurveyAnswer(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
survey = models.ForeignKey(Survey) survey = models.ForeignKey(Survey)
answers = models.ManyToManyField(SurveyQuestionAnswer, related_name="selected_by") answers = models.ManyToManyField(SurveyQuestionAnswer,
related_name="selected_by")
class Meta: class Meta:
verbose_name = "Réponses" verbose_name = "Réponses"

View file

@ -4,8 +4,9 @@ from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ 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 = ( LEVELS_CHOICES = (
('college', _(u"Collège")), ('college', _(u"Collège")),
@ -16,6 +17,7 @@ LEVELS_CHOICES = (
('other', _(u"Autre (préciser dans les commentaires)")), ('other', _(u"Autre (préciser dans les commentaires)")),
) )
class PetitCoursSubject(models.Model): class PetitCoursSubject(models.Model):
name = models.CharField(_(u"Matière"), max_length=30) name = models.CharField(_(u"Matière"), max_length=30)
users = models.ManyToManyField(User, related_name="petits_cours_matieres", users = models.ManyToManyField(User, related_name="petits_cours_matieres",
@ -28,12 +30,13 @@ class PetitCoursSubject(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
class PetitCoursAbility(models.Model): class PetitCoursAbility(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière")) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière"))
niveau = models.CharField (_(u"Niveau"), niveau = models.CharField(_(u"Niveau"),
choices=LEVELS_CHOICES, choices=LEVELS_CHOICES,
max_length=choices_length (LEVELS_CHOICES)) max_length=choices_length(LEVELS_CHOICES))
agrege = models.BooleanField(_(u"Agrégé"), default=False) agrege = models.BooleanField(_(u"Agrégé"), default=False)
class Meta: class Meta:
@ -41,7 +44,9 @@ class PetitCoursAbility(models.Model):
verbose_name_plural = "Compétences des petits cours" verbose_name_plural = "Compétences des petits cours"
def __unicode__(self): 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): class PetitCoursDemande(models.Model):
name = models.CharField(_(u"Nom/prénom"), max_length=200) 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)"), phone = models.CharField(_(u"Téléphone (facultatif)"),
max_length=20, blank=True) max_length=20, blank=True)
quand = models.CharField( quand = models.CharField(
_(u"Quand ?"), _(u"Quand ?"),
help_text=_(u"Indiquez ici la période désirée pour les petits" \ help_text=_(u"Indiquez ici la période désirée pour les petits"
+ " cours (vacances scolaires, semaine, week-end)."), " cours (vacances scolaires, semaine, week-end)."),
max_length=300, blank=True) max_length=300, blank=True)
freq = models.CharField( freq = models.CharField(
_(u"Fréquence"), _(u"Fréquence"),
help_text=_(u"Indiquez ici la fréquence envisagée " \ help_text=_(u"Indiquez ici la fréquence envisagée "
+ "(hebdomadaire, 2 fois par semaine, ...)"), + "(hebdomadaire, 2 fois par semaine, ...)"),
max_length=300, blank=True) max_length=300, blank=True)
lieu = models.CharField( lieu = models.CharField(
_(u"Lieu (si préférence)"), _(u"Lieu (si préférence)"),
help_text=_(u"Si vous avez avez une préférence sur le lieu."), help_text=_(u"Si vous avez avez une préférence sur le lieu."),
max_length=300, blank=True) max_length=300, blank=True)
matieres = models.ManyToManyField( matieres = models.ManyToManyField(
PetitCoursSubject, verbose_name=_(u"Matières"), PetitCoursSubject, verbose_name=_(u"Matières"),
related_name="demandes") related_name="demandes")
agrege_requis = models.BooleanField(_(u"Agrégé requis"), default=False) agrege_requis = models.BooleanField(_(u"Agrégé requis"), default=False)
niveau = models.CharField (_(u"Niveau"), niveau = models.CharField(_(u"Niveau"),
default="", default="",
choices=LEVELS_CHOICES, choices=LEVELS_CHOICES,
max_length=choices_length (LEVELS_CHOICES)) max_length=choices_length(LEVELS_CHOICES))
remarques = models.TextField(_(u"Remarques et précisions"), blank=True) 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" verbose_name_plural = "Demandes de petits cours"
def __unicode__(self): 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): class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
@ -94,7 +101,7 @@ class PetitCoursAttribution(models.Model):
date = models.DateTimeField(_(u"Date d'attribution"), auto_now_add=True) date = models.DateTimeField(_(u"Date d'attribution"), auto_now_add=True)
rank = models.IntegerField("Rang dans l'email") rank = models.IntegerField("Rang dans l'email")
selected = models.BooleanField(_(u"Sélectionné par le demandeur"), selected = models.BooleanField(_(u"Sélectionné par le demandeur"),
default=False) default=False)
class Meta: class Meta:
verbose_name = "Attribution de petits cours" verbose_name = "Attribution de petits cours"
@ -102,7 +109,8 @@ class PetitCoursAttribution(models.Model):
def __unicode__(self): def __unicode__(self):
return u"Attribution de la demande %d à %s pour %s" \ 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): class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
@ -115,5 +123,4 @@ class PetitCoursAttributionCounter(models.Model):
def __unicode__(self): def __unicode__(self):
return u"%d demandes envoyées à %s pour %s" \ return u"%d demandes envoyées à %s pour %s" \
% (self.count, self.user.username, self.matiere) % (self.count, self.user.username, self.matiere)

View file

@ -56,10 +56,12 @@ def details(request, demande_id):
def _get_attrib_counter(user, matiere): def _get_attrib_counter(user, matiere):
counter, created = PetitCoursAttributionCounter.objects.get_or_create(user=user, counter, created = PetitCoursAttributionCounter.\
matiere=matiere) objects.get_or_create(user=user, matiere=matiere)
if created: 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.count = mincount['count__min']
counter.save() counter.save()
return counter return counter
@ -67,14 +69,15 @@ def _get_attrib_counter(user, matiere):
def _get_demande_candidates(demande, redo=False): def _get_demande_candidates(demande, redo=False):
for matiere in demande.matieres.all(): 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, candidates = candidates.filter(user__profile__is_cof=True,
user__profile__petits_cours_accept=True) user__profile__petits_cours_accept=True)
if demande.agrege_requis: if demande.agrege_requis:
candidates = candidates.filter(agrege=True) candidates = candidates.filter(agrege=True)
if redo: if redo:
attributions = PetitCoursAttribution.objects.filter(demande=demande, attributions = PetitCoursAttribution.objects.\
matiere=matiere).all() filter(demande=demande, matiere=matiere).all()
for attrib in attributions: for attrib in attributions:
candidates = candidates.exclude(user=attrib.user) candidates = candidates.exclude(user=attrib.user)
candidates = candidates.order_by('?').select_related().all() 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", mainmail = render_template("petits-cours-mail-demandeur.txt",
{"proposals": proposals, {"proposals": proposals,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"extra": "<textarea name=\"extra\" style=\"width:99%; height: 90px;\"></textarea>"}) "extra":
'<textarea name="extra" '
'style="width:99%; height: 90px;">'
'</textarea>'
})
return render(request, "traitement_demande_petit_cours.html", return render(request, "traitement_demande_petit_cours.html",
{"demande": demande, {"demande": demande,
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
@ -139,16 +146,18 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
"proposed_for": proposed_for, "proposed_for": proposed_for,
"proposed_mails": proposed_mails, "proposed_mails": proposed_mails,
"mainmail": mainmail, "mainmail": mainmail,
"attribdata": base64.b64encode(simplejson.dumps(attribdata)), "attribdata":
base64.b64encode(simplejson.dumps(attribdata)),
"redo": redo, "redo": redo,
"errors": errors, "errors": errors,
}) })
def _generate_eleve_email(demande, proposed_for): def _generate_eleve_email(demande, proposed_for):
proposed_mails = [] proposed_mails = []
for user, matieres in proposed_for: 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)) proposed_mails.append((user, msg))
return proposed_mails return proposed_mails
@ -167,15 +176,18 @@ def _traitement_other_preparing(request, demande):
attribdata[matiere.id] = [] attribdata[matiere.id] = []
proposals[matiere] = [] proposals[matiere] = []
for choice_id in range(min(3, len(candidates))): 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: if choice == -1:
continue continue
if choice not in candidates: 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 continue
user = candidates[choice] user = candidates[choice]
if user in proposals[matiere]: 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 continue
proposals[matiere].append(user) proposals[matiere].append(user)
attribdata[matiere.id].append(user.id) attribdata[matiere.id].append(user.id)
@ -186,10 +198,14 @@ def _traitement_other_preparing(request, demande):
if not proposals[matiere]: if not proposals[matiere]:
errors.append(u"Aucune proposition pour %s" % (matiere,)) errors.append(u"Aucune proposition pour %s" % (matiere,))
elif len(proposals[matiere]) < 3: 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: else:
unsatisfied.append(matiere) 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): def _traitement_other(request, demande, redo):
@ -229,7 +245,7 @@ def _traitement_other(request, demande, redo):
"unsatisfied": unsatisfied, "unsatisfied": unsatisfied,
"proposals": proposals, "proposals": proposals,
"proposed_for": proposed_for, "proposed_for": proposed_for,
}) })
def _traitement_post(request, demande): def _traitement_post(request, demande):
@ -270,13 +286,15 @@ def _traitement_post(request, demande):
mails_to_send.append(msg) mails_to_send.append(msg)
mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail, mails_to_send.append(EmailMessage("Cours particuliers ENS", mainmail,
frommail, [demande.email], frommail, [demande.email],
[bccaddress], headers={'Reply-To': replyto})) [bccaddress],
headers={'Reply-To': replyto}))
connection = mail.get_connection(fail_silently=True) connection = mail.get_connection(fail_silently=True)
connection.send_messages(mails_to_send) connection.send_messages(mails_to_send)
lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User) lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User)
for matiere in proposals: for matiere in proposals:
for rank, user in enumerate(proposals[matiere]): 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.count += 1
counter.save() counter.save()
attrib = PetitCoursAttribution(user=user, matiere=matiere, attrib = PetitCoursAttribution(user=user, matiere=matiere,
@ -290,14 +308,15 @@ def _traitement_post(request, demande):
return render(request, "traitement_demande_petit_cours_success.html", return render(request, "traitement_demande_petit_cours_success.html",
{"demande": demande, {"demande": demande,
"redo": redo, "redo": redo,
}) })
class BaseMatieresFormSet(BaseInlineFormSet): class BaseMatieresFormSet(BaseInlineFormSet):
def clean(self): def clean(self):
super(BaseMatieresFormSet, self).clean() super(BaseMatieresFormSet, self).clean()
if any(self.errors): 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 return
matieres = [] matieres = []
for i in range(0, self.total_form_count()): for i in range(0, self.total_form_count()):
@ -308,7 +327,9 @@ class BaseMatieresFormSet(BaseInlineFormSet):
niveau = form.cleaned_data['niveau'] niveau = form.cleaned_data['niveau']
delete = form.cleaned_data['DELETE'] delete = form.cleaned_data['DELETE']
if not delete and (matiere, niveau) in matieres: 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)) matieres.append((matiere, niveau))
@ -318,7 +339,8 @@ def inscription(request):
if not profile.is_cof: if not profile.is_cof:
return redirect("cof-denied") return redirect("cof-denied")
MatieresFormSet = inlineformset_factory(User, PetitCoursAbility, MatieresFormSet = inlineformset_factory(User, PetitCoursAbility,
fields=("matiere", "niveau", "agrege",), fields=("matiere", "niveau",
"agrege",),
formset=BaseMatieresFormSet) formset=BaseMatieresFormSet)
success = False success = False
if request.method == "POST": if request.method == "POST":
@ -328,8 +350,10 @@ def inscription(request):
profile.petits_cours_accept = "receive_proposals" in request.POST profile.petits_cours_accept = "receive_proposals" in request.POST
profile.petits_cours_remarques = request.POST["remarques"] profile.petits_cours_remarques = request.POST["remarques"]
profile.save() profile.save()
lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User, PetitCoursSubject) lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User,
abilities = PetitCoursAbility.objects.filter(user=request.user).all() PetitCoursSubject)
abilities = PetitCoursAbility.objects.\
filter(user=request.user).all()
for ability in abilities: for ability in abilities:
counter = _get_attrib_counter(ability.user, ability.matiere) counter = _get_attrib_counter(ability.user, ability.matiere)
unlock_tables() unlock_tables()
@ -337,7 +361,11 @@ def inscription(request):
formset = MatieresFormSet(instance=request.user) formset = MatieresFormSet(instance=request.user)
else: else:
formset = MatieresFormSet(instance=request.user) 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): class DemandeForm(ModelForm):
captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'}) captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'})
@ -348,7 +376,8 @@ class DemandeForm(ModelForm):
class Meta: class Meta:
model = PetitCoursDemande 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} widgets = {'matieres': forms.CheckboxSelectMultiple}
@ -362,7 +391,8 @@ def demande(request):
success = True success = True
else: else:
form = DemandeForm() 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 @csrf_exempt
@ -375,4 +405,5 @@ def demande_raw(request):
success = True success = True
else: else:
form = DemandeForm() 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})

View file

@ -19,7 +19,8 @@ petitcours_patterns = [
name='petits-cours-demande-raw'), name='petits-cours-demande-raw'),
url(r'^demandes$', DemandeListView.as_view(), url(r'^demandes$', DemandeListView.as_view(),
name='petits-cours-demandes-list'), name='petits-cours-demandes-list'),
url(r'^demandes/(?P<demande_id>\d+)$', 'gestioncof.petits_cours_views.details', url(r'^demandes/(?P<demande_id>\d+)$',
'gestioncof.petits_cours_views.details',
name='petits-cours-demande-details'), name='petits-cours-demande-details'),
url(r'^demandes/(?P<demande_id>\d+)/traitement$', url(r'^demandes/(?P<demande_id>\d+)/traitement$',
'gestioncof.petits_cours_views.traitement', 'gestioncof.petits_cours_views.traitement',
@ -38,5 +39,3 @@ events_patterns = [
url(r'^(?P<event_id>\d+)$', 'gestioncof.views.event'), url(r'^(?P<event_id>\d+)$', 'gestioncof.views.event'),
url(r'^(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'), url(r'^(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'),
] ]

View file

@ -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.views import login as django_login_view
from django.contrib.auth.models import User from django.contrib.auth.models import User
from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, SurveyQuestionAnswer from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
from gestioncof.models import Event, EventRegistration, EventOption, EventOptionChoice SurveyQuestionAnswer
from gestioncof.models import Event, EventRegistration, EventOption, \
EventOptionChoice
from gestioncof.models import EventCommentField, EventCommentValue from gestioncof.models import EventCommentField, EventCommentValue
from gestioncof.shared import send_custom_mail from gestioncof.shared import send_custom_mail
from gestioncof.models import CofProfile, Clipper from gestioncof.models import CofProfile, Clipper
@ -25,8 +27,10 @@ from bda.models import Tirage
def home(request): def home(request):
data = {"surveys": Survey.objects.filter(old=False).all(), data = {"surveys": Survey.objects.filter(old=False).all(),
"events": Event.objects.filter(old=False).all(), "events": Event.objects.filter(old=False).all(),
"open_surveys": Survey.objects.filter(survey_open=True, old=False).all(), "open_surveys":
"open_events": Event.objects.filter(registration_open=True, old=False).all(), 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()} "open_tirages": Tirage.objects.filter(active=True).all()}
return render(request, "home.html", data) return render(request, "home.html", data)
@ -44,9 +48,11 @@ def login_ext(request):
if not user.has_usable_password() or user.password in ("", "!"): if not user.has_usable_password() or user.password in ("", "!"):
profile, created = CofProfile.objects.get_or_create(user=user) profile, created = CofProfile.objects.get_or_create(user=user)
if profile.login_clipper: 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: else:
return render(request, "error.html", {"error_type": "no_password"}) return render(request, "error.html",
{"error_type": "no_password"})
except User.DoesNotExist: except User.DoesNotExist:
pass pass
return django_login_view(request, template_name='login.html') return django_login_view(request, template_name='login.html')
@ -75,7 +81,8 @@ def survey(request, survey_id):
form = SurveyForm(request.POST, survey=survey) form = SurveyForm(request.POST, survey=survey)
if request.POST.get('delete'): if request.POST.get('delete'):
try: 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.delete()
current_answer = None current_answer = None
except SurveyAnswer.DoesNotExist: except SurveyAnswer.DoesNotExist:
@ -87,7 +94,8 @@ def survey(request, survey_id):
if form.is_valid(): if form.is_valid():
all_answers = [] all_answers = []
for question_id, answers_ids in form.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) survey=survey)
if type(answers_ids) != list: if type(answers_ids) != list:
answers_ids = [answers_ids] answers_ids = [answers_ids]
@ -102,21 +110,28 @@ def survey(request, survey_id):
survey_question=question) survey_question=question)
all_answers.append(answer) all_answers.append(answer)
try: try:
current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey) current_answer = SurveyAnswer.objects.get(
user=request.user, survey=survey)
except SurveyAnswer.DoesNotExist: except SurveyAnswer.DoesNotExist:
current_answer = SurveyAnswer(user=request.user, survey=survey) current_answer = SurveyAnswer(user=request.user,
survey=survey)
current_answer.save() current_answer.save()
current_answer.answers = all_answers current_answer.answers = all_answers
current_answer.save() current_answer.save()
success = True success = True
else: else:
try: try:
current_answer = SurveyAnswer.objects.get(user=request.user, survey=survey) current_answer = SurveyAnswer.objects.get(user=request.user,
form = SurveyForm(survey=survey, current_answers=current_answer.answers) survey=survey)
form = SurveyForm(survey=survey,
current_answers=current_answer.answers)
except SurveyAnswer.DoesNotExist: except SurveyAnswer.DoesNotExist:
current_answer = None current_answer = None
form = SurveyForm(survey=survey) 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): def get_event_form_choices(event, form):
@ -138,14 +153,16 @@ def get_event_form_choices(event, form):
all_choices.append(choice) all_choices.append(choice)
return all_choices return all_choices
def update_event_form_comments(event, form, registration): def update_event_form_comments(event, form, registration):
for commentfield_id, value in form.comments(): for commentfield_id, value in form.comments():
field = get_object_or_404(EventCommentField, id=commentfield_id, field = get_object_or_404(EventCommentField, id=commentfield_id,
event=event) event=event)
if value == field.default: if value == field.default:
continue continue
(storage, _) = EventCommentValue.objects.get_or_create(commentfield=field, (storage, _) = EventCommentValue.objects.get_or_create(
registration=registration) commentfield=field,
registration=registration)
storage.content = value storage.content = value
storage.save() storage.save()
@ -160,17 +177,23 @@ def event(request, event_id):
form = EventForm(request.POST, event=event) form = EventForm(request.POST, event=event)
if form.is_valid(): if form.is_valid():
all_choices = get_event_form_choices(event, form) 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.options = all_choices
current_registration.save() current_registration.save()
success = True success = True
else: else:
try: try:
current_registration = EventRegistration.objects.get(user=request.user, event=event) current_registration = \
form = EventForm(event=event, current_choices=current_registration.options) EventRegistration.objects.get(user=request.user, event=event)
form = EventForm(event=event,
current_choices=current_registration.options)
except EventRegistration.DoesNotExist: except EventRegistration.DoesNotExist:
form = EventForm(event=event) 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): def clean_post_for_status(initial):
d = initial.copy() d = initial.copy()
@ -180,6 +203,7 @@ def clean_post_for_status(initial):
d[k[3:]] = v d[k[3:]] = v
return d return d
@buro_required @buro_required
def event_status(request, event_id): def event_status(request, event_id):
event = get_object_or_404(Event, id=event_id) event = get_object_or_404(Event, id=event_id)
@ -192,15 +216,19 @@ def event_status(request, event_id):
if value == "yes": if value == "yes":
registrations_query = registrations_query.filter(paid=True) registrations_query = registrations_query.filter(paid=True)
elif value == "no": elif value == "no":
registrations_query = registrations_query.filter(paid=False) registrations_query = registrations_query.filter(
paid=False)
continue 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": if value == "none":
continue continue
if value == "yes": 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": 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() user_choices = registrations_query.prefetch_related("user").all()
options = EventOption.objects.filter(event=event).all() options = EventOption.objects.filter(event=event).all()
choices_count = {} choices_count = {}
@ -210,7 +238,10 @@ def event_status(request, event_id):
for user_choice in user_choices: for user_choice in user_choices:
for choice in user_choice.options.all(): for choice in user_choice.options.all():
choices_count[choice.id] += 1 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 @buro_required
@ -221,13 +252,16 @@ def survey_status(request, survey_id):
form = SurveyStatusFilterForm(post_data or None, survey=survey) form = SurveyStatusFilterForm(post_data or None, survey=survey)
if form.is_valid(): if form.is_valid():
for question_id, answer_id, value in form.filters(): 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": if value == "none":
continue continue
if value == "yes": 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": 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() user_answers = answers_query.prefetch_related("user").all()
questions = SurveyQuestion.objects.filter(survey=survey).all() questions = SurveyQuestion.objects.filter(survey=survey).all()
answers_count = {} answers_count = {}
@ -237,7 +271,10 @@ def survey_status(request, survey_id):
for user_answer in user_answers: for user_answer in user_answers:
for answer in user_answer.answers.all(): for answer in user_answer.answers.all():
answers_count[answer.id] += 1 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 @login_required
@ -272,7 +309,8 @@ def registration_form(request, login_clipper=None, username=None):
user_form = RegistrationUserForm() user_form = RegistrationUserForm()
profile_form = RegistrationProfileForm() profile_form = RegistrationProfileForm()
user_form.fields['username'].initial = login_clipper 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 profile_form.fields['login_clipper'].initial = login_clipper
if clipper.fullname: if clipper.fullname:
bits = clipper.fullname.split(" ") bits = clipper.fullname.split(" ")
@ -291,7 +329,10 @@ def registration_form(request, login_clipper=None, username=None):
# new user # new user
user_form = RegistrationUserForm() user_form = RegistrationUserForm()
profile_form = RegistrationProfileForm() 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 @buro_required
def registration_form2(request, login_clipper=None, username=None): 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() profile_form = RegistrationProfileForm()
event_forms = [AdminEventForm(event=event) for event in events] event_forms = [AdminEventForm(event=event) for event in events]
user_form.fields['username'].initial = login_clipper 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 profile_form.fields['login_clipper'].initial = login_clipper
if clipper.fullname: if clipper.fullname:
bits = clipper.fullname.split(" ") bits = clipper.fullname.split(" ")
@ -327,8 +369,12 @@ def registration_form2(request, login_clipper=None, username=None):
event_forms = [] event_forms = []
for event in events: for event in events:
try: try:
current_registration = EventRegistration.objects.get(user=member, event=event) current_registration = EventRegistration.objects.get(
form = AdminEventForm(event=event, current_registration=current_registration, paid=current_registration.paid) user=member, event=event)
form = AdminEventForm(
event=event,
current_registration=current_registration,
paid=current_registration.paid)
except EventRegistration.DoesNotExist: except EventRegistration.DoesNotExist:
form = AdminEventForm(event=event) form = AdminEventForm(event=event)
event_forms.append(form) event_forms.append(form)
@ -337,7 +383,10 @@ def registration_form2(request, login_clipper=None, username=None):
user_form = RegistrationUserForm() user_form = RegistrationUserForm()
profile_form = RegistrationProfileForm() profile_form = RegistrationProfileForm()
event_forms = [AdminEventForm(event=event) for event in events] 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 @buro_required
@ -350,7 +399,8 @@ def registration(request):
user_form = RegistrationUserForm(request_dict) user_form = RegistrationUserForm(request_dict)
profile_form = RegistrationProfileForm(request_dict) profile_form = RegistrationProfileForm(request_dict)
events = Event.objects.filter(old=False).all() 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() user_form.is_valid()
profile_form.is_valid() profile_form.is_valid()
for event_form in event_forms: for event_form in event_forms:
@ -363,7 +413,8 @@ def registration(request):
member = User.objects.filter(username=username).get() member = User.objects.filter(username=username).get()
(profile, _) = CofProfile.objects.get_or_create(user=member) (profile, _) = CofProfile.objects.get_or_create(user=member)
user_form = RegistrationUserForm(request_dict, instance=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: except User.DoesNotExist:
try: try:
clipper = Clipper.objects.filter(username=username).get() clipper = Clipper.objects.filter(username=username).get()
@ -376,12 +427,14 @@ def registration(request):
if form.cleaned_data['status'] == 'no': if form.cleaned_data['status'] == 'no':
continue continue
all_choices = get_event_form_choices(form.event, form) 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() member = user_form.save()
(profile, _) = CofProfile.objects.get_or_create(user=member) (profile, _) = CofProfile.objects.get_or_create(user=member)
was_cof = profile.is_cof was_cof = profile.is_cof
request_dict["num"] = profile.num 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.is_valid()
profile_form.save() profile_form.save()
(profile, _) = CofProfile.objects.get_or_create(user=member) (profile, _) = CofProfile.objects.get_or_create(user=member)
@ -390,26 +443,39 @@ def registration(request):
for form in event_forms: for form in event_forms:
if form.cleaned_data['status'] == 'no': if form.cleaned_data['status'] == 'no':
try: try:
current_registration = EventRegistration.objects.get(user=member, event=form.event) current_registration = EventRegistration.objects.get(
user=member, event=form.event)
current_registration.delete() current_registration.delete()
except EventRegistration.DoesNotExist: except EventRegistration.DoesNotExist:
pass pass
continue continue
all_choices = get_event_form_choices(form.event, form) 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) update_event_form_comments(event, form, current_registration)
current_registration.options = all_choices current_registration.options = all_choices
current_registration.paid = (form.cleaned_data['status'] == 'paid') current_registration.paid = \
(form.cleaned_data['status'] == 'paid')
current_registration.save() current_registration.save()
if event.title == "Mega 15" and created_reg: 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: try:
comments = EventCommentValue.objects.get(commentfield=field, registration=current_registration).content comments = EventCommentValue.objects.get(
commentfield=field,
registration=current_registration).content
except EventCommentValue.DoesNotExist: except EventCommentValue.DoesNotExist:
comments = field.default comments = field.default
send_custom_mail(member, "mega", {"remarques": comments}) send_custom_mail(member, "mega", {"remarques": comments})
success = True 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: else:
return render(request, "registration.html") return render(request, "registration.html")
@ -422,7 +488,9 @@ def export_members(request):
writer = unicodecsv.writer(response) writer = unicodecsv.writer(response)
for profile in CofProfile.objects.filter(is_cof=True).all(): for profile in CofProfile.objects.filter(is_cof=True).all():
user = profile.user 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]) writer.writerow([unicode(bit) for bit in bits])
return response return response
@ -437,8 +505,12 @@ def csv_export_mega(filename, qs):
for reg in qs.all(): for reg in qs.all():
user = reg.user user = reg.user
profile = user.profile profile = user.profile
comments = "---".join([comment.content for comment in reg.comments.all()]) comments = "---".join(
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments if profile.comments else "", comments] [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]) writer.writerow([unicode(bit) for bit in bits])
return response return response
@ -457,7 +529,8 @@ def export_mega_remarksonly(request):
reg = val.registration reg = val.registration
user = reg.user user = reg.user
profile = user.profile 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]) writer.writerow([unicode(bit) for bit in bits])
return response return response
@ -476,7 +549,8 @@ def export_mega_bytype(request, type):
event = Event.objects.get(title="Mega 15") event = Event.objects.get(title="Mega 15")
type_option = event.options.get(name="Type") type_option = event.options.get(name="Type")
participant_type = type_option.choices.get(value=types[type]).id 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) 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") type_option = event.options.get(name="Type")
participant_type_a = type_option.choices.get(value="Conscrit étudiant").id participant_type_a = type_option.choices.get(value="Conscrit étudiant").id
participant_type_b = type_option.choices.get(value="Conscrit élève").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) 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") type_option = event.options.get(name="Type")
participant_type_a = type_option.choices.get(value="Conscrit étudiant").id participant_type_a = type_option.choices.get(value="Conscrit étudiant").id
participant_type_b = type_option.choices.get(value="Conscrit élève").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) return csv_export_mega('participants_mega_15.csv', qs)
@buro_required @buro_required
def export_mega(request): def export_mega(request):
event = Event.objects.filter(title="Mega 15") 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) return csv_export_mega('all_mega_2015.csv', qs)
@ -522,18 +599,22 @@ def utile_bda(request):
def liste_bdadiff(request): def liste_bdadiff(request):
titre = "BdA diffusion" titre = "BdA diffusion"
personnes = CofProfile.objects.filter(mailing_bda=True, is_cof=True).all() 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 @buro_required
def liste_bdarevente(request): def liste_bdarevente(request):
titre = "BdA revente" titre = "BdA revente"
personnes = CofProfile.objects.filter(mailing_bda_revente=True, is_cof=True).all() personnes = CofProfile.objects.filter(mailing_bda_revente=True,
return render(request, "liste_mails.html", {"titre": titre, "personnes": personnes}) is_cof=True).all()
return render(request, "liste_mails.html", {"titre": titre,
"personnes": personnes})
@buro_required @buro_required
def liste_diffcof(request): def liste_diffcof(request):
titre = "Diffusion COF" titre = "Diffusion COF"
personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all() 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})

View file

@ -2,8 +2,8 @@ from django.forms.widgets import Widget
from django.forms.utils import flatatt from django.forms.utils import flatatt
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
class TriStateCheckbox(Widget):
class TriStateCheckbox(Widget):
def __init__(self, attrs=None, choices=()): def __init__(self, attrs=None, choices=()):
super(TriStateCheckbox, self).__init__(attrs) super(TriStateCheckbox, self).__init__(attrs)
# choices can be any iterable, but we may need to render this widget # choices can be any iterable, but we may need to render this widget
@ -12,7 +12,8 @@ class TriStateCheckbox(Widget):
self.choices = list(choices) self.choices = list(choices)
def render(self, name, value, attrs=None, 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) final_attrs = self.build_attrs(attrs, value=value)
output = [u"<span class=\"tristate\"%s></span>" % flatatt(final_attrs)] output = [u"<span class=\"tristate\"%s></span>" % flatatt(final_attrs)]
return mark_safe('\n'.join(output)) return mark_safe('\n'.join(output))

View file

@ -15,16 +15,19 @@ if __name__ == "__main__":
start = time.time() start = time.time()
shows = Spectacle.objects.all() shows = Spectacle.objects.all()
members = Participant.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'] available_slots = Spectacle.objects.aggregate(Sum('slots'))['slots__sum']
cursor = connection.cursor() 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] total_price = cursor.fetchone()[0]
print "%d spectacles" % len(shows) print "%d spectacles" % len(shows)
print "%d places" % available_slots print "%d places" % available_slots
print "%d participants" % len(members) print "%d participants" % len(members)
print "%d demandes" % len(choices) 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 "%.02f€ à brasser" % total_price
print "Récupération: %.2fs" % (time.time() - start) print "Récupération: %.2fs" % (time.time() - start)
start_init = time.time() start_init = time.time()
@ -54,7 +57,8 @@ if __name__ == "__main__":
members2[member].append(show) members2[member].append(show)
member.total += show.price member.total += show.price
if len(members) < show.slots: 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() members2 = members2.items()
print "Temps total: %.2fs" % (time.time() - start) print "Temps total: %.2fs" % (time.time() - start)
print "Requêtes SQL:" print "Requêtes SQL:"