Merge branch 'master' into Kerl/fix_32_do_tirage
This commit is contained in:
commit
3aa9667eb9
28 changed files with 1010 additions and 605 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ settings.py
|
||||||
venv/
|
venv/
|
||||||
.vagrant
|
.vagrant
|
||||||
/src
|
/src
|
||||||
|
media/
|
||||||
|
|
|
@ -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()
|
||||||
|
|
79
bda/admin.py
79
bda/admin.py
|
@ -4,38 +4,49 @@ 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: return u"%.02f €" % tot
|
if tot:
|
||||||
else: return u"0 €"
|
return u"%.02f €" % tot
|
||||||
|
else:
|
||||||
|
return u"0 €"
|
||||||
total.admin_order_field = "total"
|
total.admin_order_field = "total"
|
||||||
total.short_description = "Total à payer"
|
total.short_description = "Total à payer"
|
||||||
list_display = ("user", "nb_places", "total", "paid", "paymenttype",
|
list_display = ("user", "nb_places", "total", "paid", "paymenttype",
|
||||||
"tirage")
|
"tirage")
|
||||||
list_filter = ("paid", "tirage")
|
list_filter = ("paid", "tirage")
|
||||||
search_fields = ('user__username', 'user__first_name', 'user__last_name')
|
search_fields = ('user__username', 'user__first_name', 'user__last_name')
|
||||||
actions = ['send_attribs',]
|
actions = ['send_attribs', ]
|
||||||
actions_on_bottom = True
|
actions_on_bottom = True
|
||||||
list_per_page = 400
|
list_per_page = 400
|
||||||
readonly_fields = ("total",)
|
readonly_fields = ("total",)
|
||||||
|
@ -49,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
|
||||||
|
|
||||||
|
@ -69,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 :
|
||||||
|
@ -94,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"
|
||||||
|
@ -105,36 +119,48 @@ 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()
|
||||||
participant = cleaned_data.get("participant")
|
participant = cleaned_data.get("participant")
|
||||||
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
|
||||||
|
@ -142,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",
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -39,8 +41,10 @@ class Algorithm(object):
|
||||||
member_shows[member] = {}
|
member_shows[member] = {}
|
||||||
for choice in choices:
|
for choice in choices:
|
||||||
member = choice.participant
|
member = choice.participant
|
||||||
if choice.spectacle in member_shows[member]: continue
|
if choice.spectacle in member_shows[member]:
|
||||||
else: member_shows[member][choice.spectacle] = True
|
continue
|
||||||
|
else:
|
||||||
|
member_shows[member][choice.spectacle] = True
|
||||||
showdict[choice.spectacle].requests.append(member)
|
showdict[choice.spectacle].requests.append(member)
|
||||||
showdict[choice.spectacle].nrequests += 2 if choice.double else 1
|
showdict[choice.spectacle].nrequests += 2 if choice.double else 1
|
||||||
self.ranks[member][choice.spectacle] = next_rank[member]
|
self.ranks[member][choice.spectacle] = next_rank[member]
|
||||||
|
@ -49,7 +53,7 @@ class Algorithm(object):
|
||||||
for member in members:
|
for member in members:
|
||||||
self.origranks[member] = dict(self.ranks[member])
|
self.origranks[member] = dict(self.ranks[member])
|
||||||
|
|
||||||
def IncrementRanks(self, member, currank, increment = 1):
|
def IncrementRanks(self, member, currank, increment=1):
|
||||||
for show in self.ranks[member]:
|
for show in self.ranks[member]:
|
||||||
if self.ranks[member][show] > currank:
|
if self.ranks[member][show] > currank:
|
||||||
self.ranks[member][show] -= increment
|
self.ranks[member][show] -= increment
|
||||||
|
@ -63,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 = []
|
||||||
|
@ -78,23 +83,23 @@ class Algorithm(object):
|
||||||
group = list(groups[i])
|
group = list(groups[i])
|
||||||
random.shuffle(group)
|
random.shuffle(group)
|
||||||
for member in group:
|
for member in group:
|
||||||
if self.choices[member][show].double: # double
|
if self.choices[member][show].double: # double
|
||||||
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:
|
||||||
self.appendResult(losers, member, show)
|
self.appendResult(losers, member, show)
|
||||||
self.appendResult(losers, member, show)
|
self.appendResult(losers, member, show)
|
||||||
self.IncrementRanks(member, i, 2)
|
self.IncrementRanks(member, i, 2)
|
||||||
else: # simple
|
else: # simple
|
||||||
if len(winners) < show.slots:
|
if len(winners) < show.slots:
|
||||||
self.appendResult(winners, member, show)
|
self.appendResult(winners, member, show)
|
||||||
else:
|
else:
|
||||||
self.appendResult(losers, member, show)
|
self.appendResult(losers, member, show)
|
||||||
self.IncrementRanks(member, i)
|
self.IncrementRanks(member, i)
|
||||||
results.append((show,winners,losers))
|
results.append((show, winners, losers))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
|
@ -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...'})
|
||||||
|
|
18
bda/forms.py
18
bda/forms.py
|
@ -4,12 +4,14 @@ 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."""
|
||||||
super(BaseBdaFormSet, self).clean()
|
super(BaseBdaFormSet, 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
|
||||||
spectacles = []
|
spectacles = []
|
||||||
for i in range(0, self.total_form_count()):
|
for i in range(0, self.total_form_count()):
|
||||||
|
@ -19,23 +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()
|
||||||
|
|
|
@ -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")
|
||||||
|
@ -20,14 +21,16 @@ 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")
|
||||||
|
|
||||||
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")
|
||||||
|
@ -41,9 +44,9 @@ class Spectacle(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Spectacle"
|
verbose_name = "Spectacle"
|
||||||
ordering = ("priority", "date","title",)
|
ordering = ("priority", "date", "title",)
|
||||||
|
|
||||||
def __repr__ (self):
|
def __repr__(self):
|
||||||
return u"[%s]" % self.__unicode__()
|
return u"[%s]" % self.__unicode__()
|
||||||
|
|
||||||
def timestamp(self):
|
def timestamp(self):
|
||||||
|
@ -52,31 +55,33 @@ class Spectacle(models.Model):
|
||||||
def date_no_seconds(self):
|
def date_no_seconds(self):
|
||||||
return self.date.strftime('%d %b %Y %H:%M')
|
return self.date.strftime('%d %b %Y %H:%M')
|
||||||
|
|
||||||
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"),
|
||||||
("cb","CB"),
|
("cb", "CB"),
|
||||||
("cheque",u"Chèque"),
|
("cheque", u"Chèque"),
|
||||||
("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):
|
||||||
return u"%s" % (self.user)
|
return u"%s" % (self.user)
|
||||||
|
|
||||||
DOUBLE_CHOICES = (
|
DOUBLE_CHOICES = (
|
||||||
|
@ -85,12 +90,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"
|
||||||
|
@ -106,11 +113,11 @@ 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")
|
||||||
given = models.BooleanField(u"Donnée", default=False)
|
given = models.BooleanField(u"Donnée", default=False)
|
||||||
|
|
||||||
def __unicode__ (self):
|
def __unicode__(self):
|
||||||
return u"%s -- %s" % (self.participant, self.spectacle)
|
return u"%s -- %s" % (self.participant, self.spectacle)
|
||||||
|
|
||||||
|
|
|
@ -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'),
|
||||||
|
@ -21,14 +22,14 @@ urlpatterns = patterns('',
|
||||||
name='bda-etat-places'),
|
name='bda-etat-places'),
|
||||||
url(r'tirage/(?P<tirage_id>\d+)$', 'bda.views.tirage'),
|
url(r'tirage/(?P<tirage_id>\d+)$', 'bda.views.tirage'),
|
||||||
url(r'spectacles/(?P<tirage_id>\d+)$',
|
url(r'spectacles/(?P<tirage_id>\d+)$',
|
||||||
SpectacleListView.as_view() ,
|
SpectacleListView.as_view(),
|
||||||
name ="bda-liste-spectacles"),
|
name="bda-liste-spectacles"),
|
||||||
url(r'spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
url(r'spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
||||||
"bda.views.spectacle",
|
"bda.views.spectacle",
|
||||||
name="bda-spectacle"),
|
name="bda-spectacle"),
|
||||||
url(r'spectacles-ics/(?P<tirage_id>\d+)$',
|
url(r'spectacles-ics/(?P<tirage_id>\d+)$',
|
||||||
'bda.views.liste_spectacles_ics',
|
'bda.views.liste_spectacles_ics',
|
||||||
name ="bda-liste-spectacles-ics"),
|
name="bda-liste-spectacles-ics"),
|
||||||
url(r'spectacles/unpaid/(?P<tirage_id>\d+)$',
|
url(r'spectacles/unpaid/(?P<tirage_id>\d+)$',
|
||||||
"bda.views.unpaid",
|
"bda.views.unpaid",
|
||||||
name="bda-unpaid"),
|
name="bda-unpaid"),
|
||||||
|
|
144
bda/views.py
144
bda/views.py
|
@ -10,7 +10,7 @@ from django.core import serializers
|
||||||
from django.forms.models import inlineformset_factory
|
from django.forms.models import inlineformset_factory
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
|
|
||||||
|
@ -18,11 +18,13 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@cof_required
|
@cof_required
|
||||||
def etat_places(request, tirage_id):
|
def etat_places(request, tirage_id):
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
|
@ -30,13 +32,13 @@ def etat_places(request, tirage_id):
|
||||||
.filter(spectacle__tirage=tirage) \
|
.filter(spectacle__tirage=tirage) \
|
||||||
.filter(double_choice="1") \
|
.filter(double_choice="1") \
|
||||||
.all() \
|
.all() \
|
||||||
.values('spectacle','spectacle__title') \
|
.values('spectacle', 'spectacle__title') \
|
||||||
.annotate(total=models.Count('spectacle'))
|
.annotate(total=models.Count('spectacle'))
|
||||||
spectacles2 = ChoixSpectacle.objects \
|
spectacles2 = ChoixSpectacle.objects \
|
||||||
.filter(spectacle__tirage=tirage) \
|
.filter(spectacle__tirage=tirage) \
|
||||||
.exclude(double_choice="1") \
|
.exclude(double_choice="1") \
|
||||||
.all() \
|
.all() \
|
||||||
.values('spectacle','spectacle__title') \
|
.values('spectacle', 'spectacle__title') \
|
||||||
.annotate(total=models.Count('spectacle'))
|
.annotate(total=models.Count('spectacle'))
|
||||||
spectacles = tirage.spectacle_set.all()
|
spectacles = tirage.spectacle_set.all()
|
||||||
spectacles_dict = {}
|
spectacles_dict = {}
|
||||||
|
@ -50,15 +52,16 @@ def etat_places(request, tirage_id):
|
||||||
spectacles_dict[spectacle["spectacle"]].ratio = \
|
spectacles_dict[spectacle["spectacle"]].ratio = \
|
||||||
spectacles_dict[spectacle["spectacle"]].total / \
|
spectacles_dict[spectacle["spectacle"]].total / \
|
||||||
spectacles_dict[spectacle["spectacle"]].slots
|
spectacles_dict[spectacle["spectacle"]].slots
|
||||||
total += spectacle["total"]
|
total += spectacle["total"]
|
||||||
for spectacle in spectacles2:
|
for spectacle in spectacles2:
|
||||||
spectacles_dict[spectacle["spectacle"]].total += 2*spectacle["total"]
|
spectacles_dict[spectacle["spectacle"]].total += 2*spectacle["total"]
|
||||||
spectacles_dict[spectacle["spectacle"]].ratio = \
|
spectacles_dict[spectacle["spectacle"]].ratio = \
|
||||||
spectacles_dict[spectacle["spectacle"]].total / \
|
spectacles_dict[spectacle["spectacle"]].total / \
|
||||||
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):
|
||||||
data = serializers.serialize("json", queryset)
|
data = serializers.serialize("json", queryset)
|
||||||
|
@ -66,13 +69,14 @@ def _hash_queryset(queryset):
|
||||||
hasher.update(data)
|
hasher.update(data)
|
||||||
return hasher.hexdigest()
|
return hasher.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
@cof_required
|
@cof_required
|
||||||
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 = {}
|
||||||
|
@ -99,13 +103,14 @@ def places(request, tirage_id):
|
||||||
"total": total,
|
"total": total,
|
||||||
"warning": warning})
|
"warning": warning})
|
||||||
|
|
||||||
@cof_required
|
|
||||||
|
@cof_required
|
||||||
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 = []
|
||||||
|
@ -114,7 +119,8 @@ def places_ics(request, tirage_id):
|
||||||
places_dict[place.spectacle].double = True
|
places_dict[place.spectacle].double = True
|
||||||
else:
|
else:
|
||||||
place.double = False
|
place.double = False
|
||||||
place.spectacle.dtend = place.spectacle.date + timedelta(seconds=7200)
|
place.spectacle.dtend = place.spectacle.date \
|
||||||
|
+ timedelta(seconds=7200)
|
||||||
places_dict[place.spectacle] = place
|
places_dict[place.spectacle] = place
|
||||||
spectacles.append(place.spectacle)
|
spectacles.append(place.spectacle)
|
||||||
filtered_places.append(place)
|
filtered_places.append(place)
|
||||||
|
@ -122,35 +128,38 @@ def places_ics(request, tirage_id):
|
||||||
{"participant": participant,
|
{"participant": participant,
|
||||||
"places": filtered_places}, content_type="text/calendar")
|
"places": filtered_places}, content_type="text/calendar")
|
||||||
|
|
||||||
|
|
||||||
@cof_required
|
@cof_required
|
||||||
def inscription(request, tirage_id):
|
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":
|
||||||
|
@ -170,14 +179,16 @@ def inscription(request, tirage_id):
|
||||||
total_price = 0
|
total_price = 0
|
||||||
for choice in participant.choixspectacle_set.all():
|
for choice in participant.choixspectacle_set.all():
|
||||||
total_price += choice.spectacle.price
|
total_price += choice.spectacle.price
|
||||||
if choice.double: total_price += choice.spectacle.price
|
if choice.double:
|
||||||
|
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):
|
||||||
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
|
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
|
||||||
|
@ -188,8 +199,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
|
||||||
|
@ -219,8 +230,9 @@ def do_tirage(request, tirage_id):
|
||||||
data["duration"] = time.time() - start
|
data["duration"] = time.time() - start
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
members2 = {}
|
members2 = {}
|
||||||
members_uniq = {} # Participant objects are not shared accross spectacle results,
|
# Participant objects are not shared accross spectacle results,
|
||||||
# So assign a single object for each Participant id
|
# so assign a single object for each Participant id
|
||||||
|
members_uniq = {}
|
||||||
for (show, members, _) in results:
|
for (show, members, _) in results:
|
||||||
for (member, _, _, _) in members:
|
for (member, _, _, _) in members:
|
||||||
if member.id not in members_uniq:
|
if member.id not in members_uniq:
|
||||||
|
@ -235,7 +247,7 @@ def do_tirage(request, tirage_id):
|
||||||
# À partir d'ici, le tirage devient effectif
|
# À partir d'ici, le tirage devient effectif
|
||||||
Attribution.objects.filter(spectacle__tirage=tirage_elt).delete()
|
Attribution.objects.filter(spectacle__tirage=tirage_elt).delete()
|
||||||
tirage_elt.tokens += "%s\n\"\"\"%s\"\"\"\n" % (
|
tirage_elt.tokens += "%s\n\"\"\"%s\"\"\"\n" % (
|
||||||
timezone.now().strftime("%y-%m-%d %H:%M:%S"),
|
timezone.now().strftime("%y-%m-%d %H:%M:%S"),
|
||||||
form.cleaned_data['token'])
|
form.cleaned_data['token'])
|
||||||
tirage_elt.enable_do_tirage = False
|
tirage_elt.enable_do_tirage = False
|
||||||
tirage_elt.save()
|
tirage_elt.save()
|
||||||
|
@ -247,6 +259,7 @@ def do_tirage(request, tirage_id):
|
||||||
else:
|
else:
|
||||||
return render(request, "bda-attrib.html", data)
|
return render(request, "bda-attrib.html", data)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def tirage(request, tirage_id):
|
def tirage(request, tirage_id):
|
||||||
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
|
tirage_elt = get_object_or_404(Tirage, id=tirage_id)
|
||||||
|
@ -260,6 +273,7 @@ def tirage(request, tirage_id):
|
||||||
form = TokenForm()
|
form = TokenForm()
|
||||||
return render(request, "bda-token.html", {"form": form})
|
return render(request, "bda-token.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
def do_resell(request, form):
|
def do_resell(request, form):
|
||||||
spectacle = form.cleaned_data["spectacle"]
|
spectacle = form.cleaned_data["spectacle"]
|
||||||
count = form.cleaned_data["count"]
|
count = form.cleaned_data["count"]
|
||||||
|
@ -270,18 +284,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:
|
||||||
|
@ -290,7 +306,9 @@ 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
|
||||||
def spectacle(request, tirage_id, spectacle_id):
|
def spectacle(request, tirage_id, spectacle_id):
|
||||||
|
@ -300,52 +318,56 @@ def spectacle(request, tirage_id, spectacle_id):
|
||||||
participants = {}
|
participants = {}
|
||||||
for attrib in attributions:
|
for attrib in attributions:
|
||||||
participant = attrib.participant
|
participant = attrib.participant
|
||||||
participant_info = {'lastname': participant.user.last_name,
|
participant_info = {'lastname': participant.user.last_name,
|
||||||
'name': participant.user.get_full_name,
|
'name': participant.user.get_full_name,
|
||||||
'username': participant.user.username,
|
'username': participant.user.username,
|
||||||
'email': participant.user.email,
|
'email': participant.user.email,
|
||||||
'given': int(attrib.given),
|
'given': int(attrib.given),
|
||||||
'paid': participant.paid,
|
'paid': participant.paid,
|
||||||
'nb_places': 1}
|
'nb_places': 1}
|
||||||
if participant.id in participants:
|
if participant.id in participants:
|
||||||
participants[participant.id]['nb_places'] += 1
|
participants[participant.id]['nb_places'] += 1
|
||||||
participants[participant.id]['given'] += attrib.given
|
participants[participant.id]['given'] += attrib.given
|
||||||
else:
|
else:
|
||||||
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):
|
||||||
model = Spectacle
|
model = Spectacle
|
||||||
template_name = 'spectacle_list.html'
|
template_name = 'spectacle_list.html'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.tirage = get_object_or_404(Tirage, id=self.kwargs['tirage_id'])
|
self.tirage = get_object_or_404(Tirage, id=self.kwargs['tirage_id'])
|
||||||
categories = self.tirage.spectacle_set.all()
|
categories = self.tirage.spectacle_set.all()
|
||||||
return categories
|
return categories
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(SpectacleListView, self).get_context_data(**kwargs)
|
context = super(SpectacleListView, self).get_context_data(**kwargs)
|
||||||
context['tirage_id'] = self.tirage.id
|
context['tirage_id'] = self.tirage.id
|
||||||
context['tirage_name'] = self.tirage.title
|
context['tirage_name'] = self.tirage.title
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
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})
|
||||||
|
|
||||||
@buro_required
|
|
||||||
|
@buro_required
|
||||||
def liste_spectacles_ics(request, tirage_id):
|
def liste_spectacles_ics(request, tirage_id):
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
spectacles = tirage.spectacle_set.order_by("date").all()
|
spectacles = tirage.spectacle_set.order_by("date").all()
|
||||||
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")
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,12 @@ USE_TZ = True
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
# Media upload (through ImageField, SiteField)
|
||||||
|
# https://docs.djangoproject.com/en/1.9/ref/models/fields/
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
# Various additional settings
|
# Various additional settings
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
|
||||||
|
@ -148,11 +154,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():
|
||||||
|
|
47
cof/urls.py
47
cof/urls.py
|
@ -1,22 +1,28 @@
|
||||||
|
# -*-coding:utf-8 -*
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.conf.urls import patterns, include, url
|
from django.conf.urls import patterns, include, url
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
autocomplete_light.autodiscover()
|
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
admin.autodiscover()
|
|
||||||
|
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
|
||||||
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
||||||
surveys_patterns, events_patterns
|
surveys_patterns, events_patterns
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
autocomplete_light.autodiscover()
|
||||||
|
admin.autodiscover()
|
||||||
|
|
||||||
|
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
|
||||||
url(r'^bda/', include('bda.urls')),
|
url(r'^bda/', include('bda.urls')),
|
||||||
# Les exports
|
# Les exports
|
||||||
url(r'^export/', include(export_patterns)),
|
url(r'^export/', include(export_patterns)),
|
||||||
# Les petits cours
|
# Les petits cours
|
||||||
url(r'^petitcours/', include(petitcours_patterns)),
|
url(r'^petitcours/', include(petitcours_patterns)),
|
||||||
|
@ -24,40 +30,41 @@ urlpatterns = patterns('',
|
||||||
url(r'^survey/', include(surveys_patterns)),
|
url(r'^survey/', include(surveys_patterns)),
|
||||||
# Evenements
|
# Evenements
|
||||||
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
|
||||||
|
@ -66,5 +73,9 @@ urlpatterns = patterns('',
|
||||||
url(r'^utile_bda/bda_diff$', 'gestioncof.views.liste_bdadiff'),
|
url(r'^utile_bda/bda_diff$', 'gestioncof.views.liste_bdadiff'),
|
||||||
url(r'^utile_cof/diff_cof$', 'gestioncof.views.liste_diffcof'),
|
url(r'^utile_cof/diff_cof$', 'gestioncof.views.liste_diffcof'),
|
||||||
url(r'^utile_bda/bda_revente$', 'gestioncof.views.liste_bdarevente'),
|
url(r'^utile_bda/bda_revente$', 'gestioncof.views.liste_bdarevente'),
|
||||||
)
|
) + \
|
||||||
|
(static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
if settings.DEBUG
|
||||||
|
else [])
|
||||||
|
# Si on est en production, MEDIA_ROOT est servi par Apache.
|
||||||
|
# Il faut dire à Django de servir MEDIA_ROOT lui-même en développement.
|
||||||
|
|
|
@ -9,86 +9,109 @@ 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 _
|
||||||
|
|
||||||
def add_link_field(target_model='', field='', link_text=unicode, desc_text=unicode):
|
import autocomplete_light
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
def link(self, instance):
|
def link(self, instance):
|
||||||
app_name = instance._meta.app_label
|
app_name = instance._meta.app_label
|
||||||
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
|
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
|
||||||
link_obj = getattr(instance, field, None) or instance
|
link_obj = getattr(instance, field, None) or instance
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class SurveyQuestionAnswerInline(admin.TabularInline):
|
class SurveyQuestionAnswerInline(admin.TabularInline):
|
||||||
model = SurveyQuestionAnswer
|
model = SurveyQuestionAnswer
|
||||||
|
|
||||||
|
|
||||||
@add_link_field(desc_text=lambda x: "Réponses",
|
@add_link_field(desc_text=lambda x: "Réponses",
|
||||||
link_text=lambda x: "Éditer les réponses")
|
link_text=lambda x: "Éditer les réponses")
|
||||||
class SurveyQuestionInline(admin.TabularInline):
|
class SurveyQuestionInline(admin.TabularInline):
|
||||||
model = SurveyQuestion
|
model = SurveyQuestion
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
model = EventOptionChoice
|
model = EventOptionChoice
|
||||||
|
|
||||||
|
|
||||||
@add_link_field(desc_text=lambda x: "Choix",
|
@add_link_field(desc_text=lambda x: "Choix",
|
||||||
link_text=lambda x: "Éditer les choix")
|
link_text=lambda x: "Éditer les choix")
|
||||||
class EventOptionInline(admin.TabularInline):
|
class EventOptionInline(admin.TabularInline):
|
||||||
model = EventOption
|
model = EventOption
|
||||||
|
|
||||||
|
|
||||||
class EventCommentFieldInline(admin.TabularInline):
|
class EventCommentFieldInline(admin.TabularInline):
|
||||||
model = EventCommentField
|
model = EventCommentField
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
model = CofProfile
|
model = CofProfile
|
||||||
inline_classes = ("collapse open",)
|
inline_classes = ("collapse open",)
|
||||||
|
|
||||||
|
|
||||||
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('__')
|
||||||
|
|
||||||
self.short_description = short_description or self.fkattrs[-1]
|
self.short_description = short_description or self.fkattrs[-1]
|
||||||
self.admin_order_field = admin_order_field or fkeydecl
|
self.admin_order_field = admin_order_field or fkeydecl
|
||||||
|
|
||||||
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)
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def ProfileInfo(field, short_description, boolean=False):
|
def ProfileInfo(field, short_description, boolean=False):
|
||||||
def getter(self):
|
def getter(self):
|
||||||
try:
|
try:
|
||||||
|
@ -99,14 +122,17 @@ 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):
|
||||||
def is_buro(self, obj):
|
def is_buro(self, obj):
|
||||||
|
@ -116,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
|
||||||
|
@ -124,57 +151,63 @@ 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:
|
||||||
return u"%s %s (%s)" % (self.first_name, self.last_name, self.username)
|
return u"%s %s (%s)" % (self.first_name, self.last_name, self.username)
|
||||||
else:
|
else:
|
||||||
return self.username
|
return self.username
|
||||||
User.__unicode__ = user_unicode
|
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):
|
||||||
queryset.update(count=0)
|
queryset.update(count=0)
|
||||||
reset.short_description = u"Remise à zéro du compteur"
|
reset.short_description = u"Remise à zéro du compteur"
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -188,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)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.db.models import Q
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper
|
||||||
|
|
||||||
|
|
||||||
def autocomplete(request):
|
def autocomplete(request):
|
||||||
if "q" not in request.GET:
|
if "q" not in request.GET:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
@ -22,25 +23,28 @@ def autocomplete(request):
|
||||||
for bit in bits:
|
for bit in bits:
|
||||||
queries['members'] = queries['members'].filter(
|
queries['members'] = queries['members'].filter(
|
||||||
Q(user__first_name__icontains=bit)
|
Q(user__first_name__icontains=bit)
|
||||||
|Q(user__last_name__icontains=bit)
|
| Q(user__last_name__icontains=bit)
|
||||||
|Q(user__username__icontains=bit)
|
| Q(user__username__icontains=bit)
|
||||||
|Q(login_clipper__icontains=bit))
|
| Q(login_clipper__icontains=bit))
|
||||||
queries['users'] = queries['users'].filter(
|
queries['users'] = queries['users'].filter(
|
||||||
Q(first_name__icontains=bit)
|
Q(first_name__icontains=bit)
|
||||||
|Q(last_name__icontains=bit)
|
| Q(last_name__icontains=bit)
|
||||||
|Q(username__icontains=bit))
|
| Q(username__icontains=bit))
|
||||||
queries['clippers'] = queries['clippers'].filter(
|
queries['clippers'] = queries['clippers'].filter(
|
||||||
Q(fullname__icontains=bit)
|
Q(fullname__icontains=bit)
|
||||||
|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)
|
||||||
|
|
||||||
options = 0
|
options = 0
|
||||||
for query in queries.values():
|
for query in queries.values():
|
||||||
options += len(query)
|
options += len(query)
|
||||||
|
|
|
@ -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...'})
|
||||||
|
|
|
@ -3,10 +3,12 @@ from django.http import HttpResponse, HttpResponseForbidden
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.apps import apps
|
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:
|
||||||
|
@ -29,17 +31,20 @@ def export(qs, fields=None):
|
||||||
# Return CSV file to browser as download
|
# Return CSV file to browser as download
|
||||||
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()
|
||||||
if not queryset:
|
if not queryset:
|
||||||
model = apps.get_model(app_label, model_name)
|
model = apps.get_model(app_label, model_name)
|
||||||
queryset = model.objects.all()
|
queryset = model.objects.all()
|
||||||
queryset = queryset.filter(profile__is_cof = True)
|
queryset = queryset.filter(profile__is_cof=True)
|
||||||
if not fields:
|
if not fields:
|
||||||
if list_display and len(queryset.model._meta.admin.list_display) > 1:
|
if list_display and len(queryset.model._meta.admin.list_display) > 1:
|
||||||
fields = queryset.model._meta.admin.list_display
|
fields = queryset.model._meta.admin.list_display
|
||||||
|
@ -47,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 %}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django_cas_ng.decorators import user_passes_test
|
from django_cas_ng.decorators import user_passes_test
|
||||||
|
|
||||||
|
|
||||||
def is_cof(user):
|
def is_cof(user):
|
||||||
try:
|
try:
|
||||||
profile = user.profile
|
profile = user.profile
|
||||||
|
@ -8,7 +9,9 @@ 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):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -10,6 +10,7 @@ from gestioncof.models import CofProfile, EventCommentValue
|
||||||
from gestioncof.widgets import TriStateCheckbox
|
from gestioncof.widgets import TriStateCheckbox
|
||||||
from gestioncof.shared import lock_table, unlock_table
|
from gestioncof.shared import lock_table, unlock_table
|
||||||
|
|
||||||
|
|
||||||
class EventForm(forms.Form):
|
class EventForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
event = kwargs.pop("event")
|
event = kwargs.pop("event")
|
||||||
|
@ -25,21 +26,25 @@ 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 \
|
||||||
field = forms.ChoiceField(label = option.name,
|
else all_choices[option.id][0]
|
||||||
choices = choices,
|
field = forms.ChoiceField(label=option.name,
|
||||||
widget = RadioSelect,
|
choices=choices,
|
||||||
required = False,
|
widget=RadioSelect,
|
||||||
initial = initial)
|
required=False,
|
||||||
|
initial=initial)
|
||||||
field.option_id = option.id
|
field.option_id = option.id
|
||||||
self.fields["option_%d" % option.id] = field
|
self.fields["option_%d" % option.id] = field
|
||||||
|
|
||||||
|
@ -48,6 +53,7 @@ class EventForm(forms.Form):
|
||||||
if name.startswith('option_'):
|
if name.startswith('option_'):
|
||||||
yield (self.fields[name].option_id, value)
|
yield (self.fields[name].option_id, value)
|
||||||
|
|
||||||
|
|
||||||
class SurveyForm(forms.Form):
|
class SurveyForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
survey = kwargs.pop("survey")
|
survey = kwargs.pop("survey")
|
||||||
|
@ -61,21 +67,25 @@ 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\
|
||||||
field = forms.ChoiceField(label = question.question,
|
else answers[question.id][0]
|
||||||
choices = choices,
|
field = forms.ChoiceField(label=question.question,
|
||||||
widget = RadioSelect,
|
choices=choices,
|
||||||
required = False,
|
widget=RadioSelect,
|
||||||
initial = initial)
|
required=False,
|
||||||
|
initial=initial)
|
||||||
field.question_id = question.id
|
field.question_id = question.id
|
||||||
self.fields["question_%d" % question.id] = field
|
self.fields["question_%d" % question.id] = field
|
||||||
|
|
||||||
|
@ -83,7 +93,8 @@ class SurveyForm(forms.Form):
|
||||||
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, value)
|
yield (self.fields[name].question_id, value)
|
||||||
|
|
||||||
|
|
||||||
class SurveyStatusFilterForm(forms.Form):
|
class SurveyStatusFilterForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
survey = kwargs.pop("survey")
|
survey = kwargs.pop("survey")
|
||||||
|
@ -91,15 +102,17 @@ 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" % (question.question, answer.answer),
|
||||||
widget = TriStateCheckbox,
|
choices=[("yes", "yes"), ("no", "no"), ("none", "none")],
|
||||||
required = False,
|
widget=TriStateCheckbox,
|
||||||
initial = initial)
|
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
|
||||||
|
@ -107,7 +120,9 @@ 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):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -116,15 +131,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
|
||||||
|
@ -134,20 +151,23 @@ class EventStatusFilterForm(forms.Form):
|
||||||
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 = "Événement payé",
|
field = forms.ChoiceField(label="Événement payé",
|
||||||
choices = [("yes", "yes"),("no","no"),("none","none")],
|
choices=[("yes", "yes"), ("no", "no"),
|
||||||
widget = TriStateCheckbox,
|
("none", "none")],
|
||||||
required = False,
|
widget=TriStateCheckbox,
|
||||||
initial = initial)
|
required=False,
|
||||||
|
initial=initial)
|
||||||
self.fields[name] = field
|
self.fields[name] = field
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
class UserProfileForm(forms.ModelForm):
|
class UserProfileForm(forms.ModelForm):
|
||||||
first_name = forms.CharField(label=_(u'Prénom'), max_length=30)
|
first_name = forms.CharField(label=_(u'Prénom'), max_length=30)
|
||||||
last_name = forms.CharField(label=_(u'Nom'), max_length=30)
|
last_name = forms.CharField(label=_(u'Nom'), max_length=30)
|
||||||
|
@ -174,7 +194,9 @@ 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):
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
|
@ -185,6 +207,7 @@ class RegistrationUserForm(forms.ModelForm):
|
||||||
model = User
|
model = User
|
||||||
fields = ("username", "first_name", "last_name", "email")
|
fields = ("username", "first_name", "last_name", "email")
|
||||||
|
|
||||||
|
|
||||||
class RegistrationProfileForm(forms.ModelForm):
|
class RegistrationProfileForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
super(RegistrationProfileForm, self).__init__(*args, **kw)
|
super(RegistrationProfileForm, self).__init__(*args, **kw)
|
||||||
|
@ -224,27 +247,33 @@ 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'),
|
||||||
|
('wait', 'Oui mais attente paiement'),
|
||||||
|
('paid', 'Oui payé'),)
|
||||||
|
|
||||||
STATUS_CHOICES = (('no','Non'),
|
|
||||||
('wait','Oui mais attente paiement'),
|
|
||||||
('paid','Oui payé'),)
|
|
||||||
|
|
||||||
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 == True:
|
if paid is True:
|
||||||
kwargs["initial"] = {"status":"paid"}
|
kwargs["initial"] = {"status": "paid"}
|
||||||
elif paid == False:
|
elif paid is False:
|
||||||
kwargs["initial"] = {"status":"wait"}
|
kwargs["initial"] = {"status": "wait"}
|
||||||
else:
|
else:
|
||||||
kwargs["initial"] = {"status":"no"}
|
kwargs["initial"] = {"status": "no"}
|
||||||
super(AdminEventForm, self).__init__(*args, **kwargs)
|
super(AdminEventForm, self).__init__(*args, **kwargs)
|
||||||
choices = {}
|
choices = {}
|
||||||
for choice in current_choices:
|
for choice in current_choices:
|
||||||
|
@ -254,35 +283,41 @@ 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\
|
||||||
field = forms.ChoiceField(label = option.name,
|
else all_choices[option.id][0]
|
||||||
choices = choices,
|
field = forms.ChoiceField(label=option.name,
|
||||||
widget = RadioSelect,
|
choices=choices,
|
||||||
required = False,
|
widget=RadioSelect,
|
||||||
initial = initial)
|
required=False,
|
||||||
|
initial=initial)
|
||||||
field.option_id = option.id
|
field.option_id = option.id
|
||||||
self.fields["option_%d" % option.id] = field
|
self.fields["option_%d" % option.id] = field
|
||||||
for commentfield in event.commentfields.all():
|
for commentfield in event.commentfields.all():
|
||||||
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" \
|
||||||
field = forms.CharField(label = commentfield.name,
|
else forms.TextInput
|
||||||
widget = widget,
|
field = forms.CharField(label=commentfield.name,
|
||||||
required = False,
|
widget=widget,
|
||||||
initial = initial)
|
required=False,
|
||||||
|
initial=initial)
|
||||||
field.comment_id = commentfield.id
|
field.comment_id = commentfield.id
|
||||||
self.fields["comment_%d" % commentfield.id] = field
|
self.fields["comment_%d" % commentfield.id] = field
|
||||||
|
|
||||||
|
@ -295,4 +330,3 @@ class AdminEventForm(forms.Form):
|
||||||
for name, value in self.cleaned_data.items():
|
for name, value in self.cleaned_data.items():
|
||||||
if name.startswith('comment_'):
|
if name.startswith('comment_'):
|
||||||
yield (self.fields[name].comment_id, value)
|
yield (self.fields[name].comment_id, value)
|
||||||
|
|
||||||
|
|
19
gestioncof/migrations/0003_event_image.py
Normal file
19
gestioncof/migrations/0003_event_image.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('gestioncof', '0002_enable_unprocessed_demandes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='image',
|
||||||
|
field=models.ImageField(upload_to=b'imgs/events/', null=True, verbose_name=b'Image', blank=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -29,32 +29,41 @@ TYPE_COMMENT_FIELD = (
|
||||||
('char', _(u"Texte court")),
|
('char', _(u"Texte court")),
|
||||||
)
|
)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
class CofProfile(models.Model):
|
class CofProfile(models.Model):
|
||||||
user = models.OneToOneField(User, related_name = "profile")
|
user = models.OneToOneField(User, related_name="profile")
|
||||||
login_clipper = models.CharField("Login clipper", max_length = 8, blank = True)
|
login_clipper = models.CharField("Login clipper", max_length=8, blank=True)
|
||||||
is_cof = models.BooleanField("Membre du COF", default = False)
|
is_cof = models.BooleanField("Membre du COF", default=False)
|
||||||
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))
|
||||||
type_cotiz = models.CharField (_(u"Type de cotisation"),
|
departement = models.CharField(_(u"Département"), max_length=50,
|
||||||
default = "normalien",
|
blank=True)
|
||||||
choices = TYPE_COTIZ_CHOICES,
|
type_cotiz = models.CharField(_(u"Type de cotisation"),
|
||||||
max_length = choices_length (TYPE_COTIZ_CHOICES))
|
default="normalien",
|
||||||
mailing_cof = models.BooleanField("Recevoir les mails COF", default = False)
|
choices=TYPE_COTIZ_CHOICES,
|
||||||
mailing_bda = models.BooleanField("Recevoir les mails BdA", default = False)
|
max_length=choices_length(
|
||||||
mailing_bda_revente = models.BooleanField("Recevoir les mails de revente de places BdA", default = False)
|
TYPE_COTIZ_CHOICES))
|
||||||
comments = models.TextField("Commentaires visibles uniquement par le Buro", blank = True)
|
mailing_cof = models.BooleanField("Recevoir les mails COF", default=False)
|
||||||
is_buro = models.BooleanField("Membre du Burô", default = False)
|
mailing_bda = models.BooleanField("Recevoir les mails BdA", default=False)
|
||||||
petits_cours_accept = models.BooleanField("Recevoir des petits cours", default = False)
|
mailing_bda_revente = models.BooleanField(
|
||||||
petits_cours_remarques = models.TextField(_(u"Remarques et précisions pour les petits cours"),
|
"Recevoir les mails de revente de places BdA", default=False)
|
||||||
blank = True, default = "")
|
comments = models.TextField(
|
||||||
|
"Commentaires visibles uniquement par le Buro", blank=True)
|
||||||
|
is_buro = models.BooleanField("Membre du Burô", default=False)
|
||||||
|
petits_cours_accept = models.BooleanField(
|
||||||
|
"Recevoir des petits cours", default=False)
|
||||||
|
petits_cours_remarques = models.TextField(
|
||||||
|
_(u"Remarques et précisions pour les petits cours"),
|
||||||
|
blank=True, default="")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Profil COF"
|
verbose_name = "Profil COF"
|
||||||
|
@ -63,22 +72,26 @@ class CofProfile(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.user.username)
|
return unicode(self.user.username)
|
||||||
|
|
||||||
|
|
||||||
def create_user_profile(sender, instance, created, **kwargs):
|
def create_user_profile(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
CofProfile.objects.get_or_create(user = instance)
|
CofProfile.objects.get_or_create(user=instance)
|
||||||
post_save.connect(create_user_profile, sender = User)
|
post_save.connect(create_user_profile, sender=User)
|
||||||
|
|
||||||
|
|
||||||
class Club(models.Model):
|
class Club(models.Model):
|
||||||
name = models.CharField("Nom", max_length = 200)
|
name = models.CharField("Nom", max_length=200)
|
||||||
description = models.TextField("Description")
|
description = models.TextField("Description")
|
||||||
respos = models.ManyToManyField(User, related_name = "clubs_geres")
|
respos = models.ManyToManyField(User, related_name="clubs_geres")
|
||||||
membres = models.ManyToManyField(User, related_name = "clubs")
|
membres = models.ManyToManyField(User, related_name="clubs")
|
||||||
|
|
||||||
|
|
||||||
class CustomMail(models.Model):
|
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"
|
||||||
|
@ -86,14 +99,18 @@ class CustomMail(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"%s: %s" % (self.shortname, self.title)
|
return u"%s: %s" % (self.shortname, self.title)
|
||||||
|
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
title = models.CharField("Titre", max_length = 200)
|
title = models.CharField("Titre", max_length=200)
|
||||||
location = models.CharField("Lieu", max_length = 200)
|
location = models.CharField("Lieu", max_length=200)
|
||||||
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)
|
image = models.ImageField("Image", blank=True, null=True,
|
||||||
old = models.BooleanField("Archiver (événement fini)", default = False)
|
upload_to="imgs/events/")
|
||||||
|
registration_open = models.BooleanField("Inscriptions ouvertes",
|
||||||
|
default=True)
|
||||||
|
old = models.BooleanField("Archiver (événement fini)", default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Événement"
|
verbose_name = "Événement"
|
||||||
|
@ -101,11 +118,13 @@ class Event(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.title)
|
return unicode(self.title)
|
||||||
|
|
||||||
|
|
||||||
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,
|
||||||
default = models.TextField("Valeur par défaut", blank = True)
|
choices=TYPE_COMMENT_FIELD, default="text")
|
||||||
|
default = models.TextField("Valeur par défaut", blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Champ"
|
verbose_name = "Champ"
|
||||||
|
@ -113,15 +132,18 @@ class EventCommentField(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.name)
|
return unicode(self.name)
|
||||||
|
|
||||||
|
|
||||||
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",
|
||||||
content = models.TextField("Contenu", blank = True, null = True)
|
related_name="comments")
|
||||||
|
content = models.TextField("Contenu", blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
class EventOption(models.Model):
|
class EventOption(models.Model):
|
||||||
event = models.ForeignKey(Event, related_name = "options")
|
event = models.ForeignKey(Event, related_name="options")
|
||||||
name = models.CharField("Option", max_length = 200)
|
name = models.CharField("Option", max_length=200)
|
||||||
multi_choices = models.BooleanField("Choix multiples", default = False)
|
multi_choices = models.BooleanField("Choix multiples", default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Option"
|
verbose_name = "Option"
|
||||||
|
@ -129,9 +151,10 @@ class EventOption(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.name)
|
return unicode(self.name)
|
||||||
|
|
||||||
|
|
||||||
class EventOptionChoice(models.Model):
|
class EventOptionChoice(models.Model):
|
||||||
event_option = models.ForeignKey(EventOption, related_name = "choices")
|
event_option = models.ForeignKey(EventOption, related_name="choices")
|
||||||
value = models.CharField("Valeur", max_length = 200)
|
value = models.CharField("Valeur", max_length=200)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Choix"
|
verbose_name = "Choix"
|
||||||
|
@ -139,25 +162,29 @@ class EventOptionChoice(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.value)
|
return unicode(self.value)
|
||||||
|
|
||||||
|
|
||||||
class EventRegistration(models.Model):
|
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,
|
||||||
paid = models.BooleanField("A payé", default = False)
|
through=EventCommentValue)
|
||||||
|
paid = models.BooleanField("A payé", default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Inscription"
|
verbose_name = "Inscription"
|
||||||
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):
|
||||||
title = models.CharField("Titre", max_length = 200)
|
title = models.CharField("Titre", max_length=200)
|
||||||
details = models.TextField("Détails", blank = True)
|
details = models.TextField("Détails", blank=True)
|
||||||
survey_open = models.BooleanField("Sondage ouvert", default = True)
|
survey_open = models.BooleanField("Sondage ouvert", default=True)
|
||||||
old = models.BooleanField("Archiver (sondage fini)", default = False)
|
old = models.BooleanField("Archiver (sondage fini)", default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Sondage"
|
verbose_name = "Sondage"
|
||||||
|
@ -165,10 +192,11 @@ class Survey(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.title)
|
return unicode(self.title)
|
||||||
|
|
||||||
|
|
||||||
class SurveyQuestion(models.Model):
|
class SurveyQuestion(models.Model):
|
||||||
survey = models.ForeignKey(Survey, related_name = "questions")
|
survey = models.ForeignKey(Survey, related_name="questions")
|
||||||
question = models.CharField("Question", max_length = 200)
|
question = models.CharField("Question", max_length=200)
|
||||||
multi_answers = models.BooleanField("Choix multiples", default = False)
|
multi_answers = models.BooleanField("Choix multiples", default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Question"
|
verbose_name = "Question"
|
||||||
|
@ -176,9 +204,10 @@ class SurveyQuestion(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.question)
|
return unicode(self.question)
|
||||||
|
|
||||||
|
|
||||||
class SurveyQuestionAnswer(models.Model):
|
class SurveyQuestionAnswer(models.Model):
|
||||||
survey_question = models.ForeignKey(SurveyQuestion, related_name = "answers")
|
survey_question = models.ForeignKey(SurveyQuestion, related_name="answers")
|
||||||
answer = models.CharField("Réponse", max_length = 200)
|
answer = models.CharField("Réponse", max_length=200)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Réponse"
|
verbose_name = "Réponse"
|
||||||
|
@ -186,15 +215,18 @@ class SurveyQuestionAnswer(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.answer)
|
return unicode(self.answer)
|
||||||
|
|
||||||
|
|
||||||
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"
|
||||||
unique_together = ("user", "survey")
|
unique_together = ("user", "survey")
|
||||||
|
|
||||||
|
|
||||||
class Clipper(models.Model):
|
class Clipper(models.Model):
|
||||||
username = models.CharField("Identifiant", max_length = 20)
|
username = models.CharField("Identifiant", max_length=20)
|
||||||
fullname = models.CharField("Nom complet", max_length = 200)
|
fullname = models.CharField("Nom complet", max_length=200)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -26,58 +26,67 @@ from datetime import datetime
|
||||||
import base64
|
import base64
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
|
|
||||||
def render_template(template_path, data):
|
def render_template(template_path, data):
|
||||||
tmpl = loader.get_template(template_path)
|
tmpl = loader.get_template(template_path)
|
||||||
context = Context(data)
|
context = Context(data)
|
||||||
return tmpl.render(context)
|
return tmpl.render(context)
|
||||||
|
|
||||||
|
|
||||||
class DemandeListView(ListView):
|
class DemandeListView(ListView):
|
||||||
model = PetitCoursDemande
|
model = PetitCoursDemande
|
||||||
template_name = "petits_cours_demandes_list.html"
|
template_name = "petits_cours_demandes_list.html"
|
||||||
paginate_by = 20
|
paginate_by = 20
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return PetitCoursDemande.objects.order_by('traitee','-id').all()
|
return PetitCoursDemande.objects.order_by('traitee', '-id').all()
|
||||||
|
|
||||||
@method_decorator(buro_required)
|
@method_decorator(buro_required)
|
||||||
def dispatch(self, *args, **kwargs):
|
def dispatch(self, *args, **kwargs):
|
||||||
return super(DemandeListView, self).dispatch(*args, **kwargs)
|
return super(DemandeListView, self).dispatch(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def details(request, demande_id):
|
def details(request, demande_id):
|
||||||
demande = get_object_or_404(PetitCoursDemande, id = demande_id)
|
demande = get_object_or_404(PetitCoursDemande, id=demande_id)
|
||||||
attributions = PetitCoursAttribution.objects.filter(demande = demande).all()
|
attributions = PetitCoursAttribution.objects.filter(demande=demande).all()
|
||||||
return render(request, "details_demande_petit_cours.html",
|
return render(request, "details_demande_petit_cours.html",
|
||||||
{"demande": demande,
|
{"demande": demande,
|
||||||
"attributions": attributions})
|
"attributions": attributions})
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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,
|
||||||
candidates = candidates.filter(user__profile__is_cof = True,
|
niveau=demande.niveau)
|
||||||
user__profile__petits_cours_accept = True)
|
candidates = candidates.filter(user__profile__is_cof=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()
|
||||||
yield (matiere, candidates)
|
yield (matiere, candidates)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def traitement(request, demande_id, redo = False):
|
def traitement(request, demande_id, redo=False):
|
||||||
demande = get_object_or_404(PetitCoursDemande, id = demande_id)
|
demande = get_object_or_404(PetitCoursDemande, id=demande_id)
|
||||||
if demande.niveau == "other":
|
if demande.niveau == "other":
|
||||||
return _traitement_other(request, demande, redo)
|
return _traitement_other(request, demande, redo)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -92,7 +101,7 @@ def traitement(request, demande_id, redo = False):
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
user = candidate.user
|
user = candidate.user
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
||||||
tuples = sorted(tuples, key = lambda c: c[1].count)
|
tuples = sorted(tuples, key=lambda c: c[1].count)
|
||||||
candidates, _ = zip(*tuples)
|
candidates, _ = zip(*tuples)
|
||||||
candidates = candidates[0:min(3, len(candidates))]
|
candidates = candidates[0:min(3, len(candidates))]
|
||||||
attribdata[matiere.id] = []
|
attribdata[matiere.id] = []
|
||||||
|
@ -110,12 +119,14 @@ def traitement(request, demande_id, redo = False):
|
||||||
return _finalize_traitement(request, demande, proposals,
|
return _finalize_traitement(request, demande, proposals,
|
||||||
proposed_for, unsatisfied, attribdata, redo)
|
proposed_for, unsatisfied, attribdata, redo)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def retraitement(request, demande_id):
|
def retraitement(request, demande_id):
|
||||||
return traitement(request, demande_id, redo = True)
|
return traitement(request, demande_id, redo=True)
|
||||||
|
|
||||||
|
|
||||||
def _finalize_traitement(request, demande, proposals, proposed_for,
|
def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
unsatisfied, attribdata, redo = False, errors = None):
|
unsatisfied, attribdata, redo=False, errors=None):
|
||||||
proposals = proposals.items()
|
proposals = proposals.items()
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
attribdata = attribdata.items()
|
attribdata = attribdata.items()
|
||||||
|
@ -123,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,
|
||||||
|
@ -131,18 +146,22 @@ 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
|
||||||
|
|
||||||
|
|
||||||
def _traitement_other_preparing(request, demande):
|
def _traitement_other_preparing(request, demande):
|
||||||
redo = "redo" in request.POST
|
redo = "redo" in request.POST
|
||||||
unsatisfied = []
|
unsatisfied = []
|
||||||
|
@ -157,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)
|
||||||
|
@ -176,10 +198,15 @@ 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):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -197,7 +224,7 @@ def _traitement_other(request, demande, redo):
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
user = candidate.user
|
user = candidate.user
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
||||||
tuples = sorted(tuples, key = lambda c: c[1].count)
|
tuples = sorted(tuples, key=lambda c: c[1].count)
|
||||||
candidates, _ = zip(*tuples)
|
candidates, _ = zip(*tuples)
|
||||||
attribdata[matiere.id] = []
|
attribdata[matiere.id] = []
|
||||||
proposals[matiere] = []
|
proposals[matiere] = []
|
||||||
|
@ -218,7 +245,8 @@ 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):
|
||||||
proposals = {}
|
proposals = {}
|
||||||
|
@ -234,7 +262,7 @@ def _traitement_post(request, demande):
|
||||||
else:
|
else:
|
||||||
proposals[matiere] = []
|
proposals[matiere] = []
|
||||||
for user_id in attribdata[matiere.id]:
|
for user_id in attribdata[matiere.id]:
|
||||||
user = User.objects.get(pk = user_id)
|
user = User.objects.get(pk=user_id)
|
||||||
proposals[matiere].append(user)
|
proposals[matiere].append(user)
|
||||||
if user not in proposed_for:
|
if user not in proposed_for:
|
||||||
proposed_for[user] = [matiere]
|
proposed_for[user] = [matiere]
|
||||||
|
@ -254,21 +282,23 @@ def _traitement_post(request, demande):
|
||||||
for (user, msg) in proposed_mails:
|
for (user, msg) in proposed_mails:
|
||||||
msg = EmailMessage("Petits cours ENS par le COF", msg,
|
msg = EmailMessage("Petits cours ENS par le COF", msg,
|
||||||
frommail, [user.email],
|
frommail, [user.email],
|
||||||
[bccaddress], headers = {'Reply-To': replyto})
|
[bccaddress], headers={'Reply-To': replyto})
|
||||||
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],
|
||||||
connection = mail.get_connection(fail_silently = True)
|
headers={'Reply-To': replyto}))
|
||||||
|
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,
|
||||||
demande = demande, rank = rank + 1)
|
demande=demande, rank=rank + 1)
|
||||||
attrib.save()
|
attrib.save()
|
||||||
unlock_tables()
|
unlock_tables()
|
||||||
demande.traitee = True
|
demande.traitee = True
|
||||||
|
@ -278,13 +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()):
|
||||||
|
@ -295,38 +327,48 @@ 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))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def inscription(request):
|
def inscription(request):
|
||||||
profile, created = CofProfile.objects.get_or_create(user = request.user)
|
profile, created = CofProfile.objects.get_or_create(user=request.user)
|
||||||
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",
|
||||||
formset = BaseMatieresFormSet)
|
"agrege",),
|
||||||
|
formset=BaseMatieresFormSet)
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
formset = MatieresFormSet(request.POST, instance = request.user)
|
formset = MatieresFormSet(request.POST, instance=request.user)
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
formset.save()
|
formset.save()
|
||||||
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()
|
||||||
success = True
|
success = True
|
||||||
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'})
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DemandeForm, self).__init__(*args, **kwargs)
|
super(DemandeForm, self).__init__(*args, **kwargs)
|
||||||
|
@ -334,9 +376,11 @@ 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}
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def demande(request):
|
def demande(request):
|
||||||
success = False
|
success = False
|
||||||
|
@ -347,7 +391,9 @@ 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
|
||||||
def demande_raw(request):
|
def demande_raw(request):
|
||||||
|
@ -359,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})
|
||||||
|
|
|
@ -12,17 +12,18 @@ from gestioncof.models import CofProfile, CustomMail
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class COFCASBackend(CASBackend):
|
class COFCASBackend(CASBackend):
|
||||||
def authenticate_cas(self, ticket, service, request):
|
def authenticate_cas(self, ticket, service, request):
|
||||||
"""Verifies CAS ticket and gets or creates User object"""
|
"""Verifies CAS ticket and gets or creates User object"""
|
||||||
|
|
||||||
client = get_cas_client(service_url=service)
|
client = get_cas_client(service_url=service)
|
||||||
username, attributes, _= client.verify_ticket(ticket)
|
username, attributes, _ = client.verify_ticket(ticket)
|
||||||
if attributes:
|
if attributes:
|
||||||
request.session['attributes'] = attributes
|
request.session['attributes'] = attributes
|
||||||
if not username:
|
if not username:
|
||||||
return None
|
return None
|
||||||
profiles = CofProfile.objects.filter(login_clipper = username)
|
profiles = CofProfile.objects.filter(login_clipper=username)
|
||||||
if len(profiles) > 0:
|
if len(profiles) > 0:
|
||||||
profile = profiles.order_by('-is_cof')[0]
|
profile = profiles.order_by('-is_cof')[0]
|
||||||
user = profile.user
|
user = profile.user
|
||||||
|
@ -43,7 +44,7 @@ class COFCASBackend(CASBackend):
|
||||||
try:
|
try:
|
||||||
profile = user.profile
|
profile = user.profile
|
||||||
except CofProfile.DoesNotExist:
|
except CofProfile.DoesNotExist:
|
||||||
profile, created = CofProfile.objects.get_or_create(user = user)
|
profile, created = CofProfile.objects.get_or_create(user=user)
|
||||||
profile.save()
|
profile.save()
|
||||||
if not profile.login_clipper:
|
if not profile.login_clipper:
|
||||||
profile.login_clipper = user.username
|
profile.login_clipper = user.username
|
||||||
|
@ -57,7 +58,8 @@ class COFCASBackend(CASBackend):
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
def context_processor (request):
|
|
||||||
|
def context_processor(request):
|
||||||
'''Append extra data to the context of the given request'''
|
'''Append extra data to the context of the given request'''
|
||||||
data = {
|
data = {
|
||||||
"user": request.user,
|
"user": request.user,
|
||||||
|
@ -65,17 +67,20 @@ def context_processor (request):
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def lock_table(*models):
|
def lock_table(*models):
|
||||||
query = "LOCK TABLES "
|
query = "LOCK TABLES "
|
||||||
for i, model in enumerate(models):
|
for i, model in enumerate(models):
|
||||||
table = model._meta.db_table
|
table = model._meta.db_table
|
||||||
if i > 0: query += ", "
|
if i > 0:
|
||||||
|
query += ", "
|
||||||
query += "%s WRITE" % table
|
query += "%s WRITE" % table
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
||||||
def unlock_tables(*models):
|
def unlock_tables(*models):
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute("UNLOCK TABLES")
|
cursor.execute("UNLOCK TABLES")
|
||||||
|
@ -84,15 +89,17 @@ def unlock_tables(*models):
|
||||||
|
|
||||||
unlock_table = unlock_tables
|
unlock_table = unlock_tables
|
||||||
|
|
||||||
def send_custom_mail(to, shortname, context = None, from_email = "cof@ens.fr"):
|
|
||||||
if context is None: context = {}
|
def send_custom_mail(to, shortname, context=None, from_email="cof@ens.fr"):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
if isinstance(to, DjangoUser):
|
if isinstance(to, DjangoUser):
|
||||||
context["nom"] = to.get_full_name()
|
context["nom"] = to.get_full_name()
|
||||||
context["prenom"] = to.first_name
|
context["prenom"] = to.first_name
|
||||||
to = to.email
|
to = to.email
|
||||||
mail = CustomMail.objects.get(shortname = shortname)
|
mail = CustomMail.objects.get(shortname=shortname)
|
||||||
template = Template(mail.content)
|
template = Template(mail.content)
|
||||||
message = template.render(Context(context))
|
message = template.render(Context(context))
|
||||||
send_mail (mail.title, message,
|
send_mail(mail.title, message,
|
||||||
from_email, [to],
|
from_email, [to],
|
||||||
fail_silently = True)
|
fail_silently=True)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<h2>Inscription d'un nouveau membre</h2>
|
<h2>Inscription d'un nouveau membre</h2>
|
||||||
<input type="text" name="q" id="search_autocomplete" spellcheck="false" />
|
<input type="text" name="q" id="search_autocomplete" spellcheck="false" />
|
||||||
<div id="form-placeholder"></div>
|
<div id="form-placeholder"></div>
|
||||||
|
<span class="yourlabs-autocomplete"></span>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('input#search_autocomplete').yourlabsAutocomplete({
|
$('input#search_autocomplete').yourlabsAutocomplete({
|
||||||
|
@ -18,6 +19,9 @@
|
||||||
id: 'search_autocomplete',
|
id: 'search_autocomplete',
|
||||||
choiceSelector: 'li:has(a)',
|
choiceSelector: 'li:has(a)',
|
||||||
placeholder: "Chercher un utilisateur par nom, prénom ou identifiant clipper",
|
placeholder: "Chercher un utilisateur par nom, prénom ou identifiant clipper",
|
||||||
|
container: $("#main-content"),
|
||||||
|
box: $(".yourlabs-autocomplete"),
|
||||||
|
fixPosition: function() {},
|
||||||
});
|
});
|
||||||
$('input#search_autocomplete').bind(
|
$('input#search_autocomplete').bind(
|
||||||
'selectChoice',
|
'selectChoice',
|
||||||
|
|
|
@ -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'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -20,70 +22,81 @@ from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
|
||||||
|
|
||||||
from bda.models import Tirage
|
from bda.models import Tirage
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
def login(request):
|
def login(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
return redirect("gestioncof.views.home")
|
return redirect("gestioncof.views.home")
|
||||||
return render(request, "login_switch.html", {})
|
return render(request, "login_switch.html", {})
|
||||||
|
|
||||||
|
|
||||||
def login_ext(request):
|
def login_ext(request):
|
||||||
if request.method == "POST" and "username" in request.POST:
|
if request.method == "POST" and "username" in request.POST:
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(username = request.POST["username"])
|
user = User.objects.get(username=request.POST["username"])
|
||||||
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')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def logout(request):
|
def logout(request):
|
||||||
try:
|
try:
|
||||||
profile = request.user.profile
|
profile = request.user.profile
|
||||||
except CofProfile.DoesNotExist:
|
except CofProfile.DoesNotExist:
|
||||||
profile, created = CofProfile.objects.get_or_create(user = request.user)
|
profile, created = CofProfile.objects.get_or_create(user=request.user)
|
||||||
if profile.login_clipper:
|
if profile.login_clipper:
|
||||||
return redirect("django_cas_ng.views.logout")
|
return redirect("django_cas_ng.views.logout")
|
||||||
else:
|
else:
|
||||||
return redirect("django.contrib.auth.views.logout")
|
return redirect("django.contrib.auth.views.logout")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def survey(request, survey_id):
|
def survey(request, survey_id):
|
||||||
survey = get_object_or_404(Survey, id = survey_id)
|
survey = get_object_or_404(Survey, id=survey_id)
|
||||||
if not survey.survey_open:
|
if not survey.survey_open:
|
||||||
raise Http404
|
raise Http404
|
||||||
success = False
|
success = False
|
||||||
deleted = False
|
deleted = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
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:
|
||||||
current_answer = None
|
current_answer = None
|
||||||
form = SurveyForm(survey = survey)
|
form = SurveyForm(survey=survey)
|
||||||
success = True
|
success = True
|
||||||
deleted = True
|
deleted = True
|
||||||
else:
|
else:
|
||||||
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,
|
||||||
survey = survey)
|
id=question_id,
|
||||||
|
survey=survey)
|
||||||
if type(answers_ids) != list:
|
if type(answers_ids) != list:
|
||||||
answers_ids = [answers_ids]
|
answers_ids = [answers_ids]
|
||||||
if not question.multi_answers and len(answers_ids) > 1:
|
if not question.multi_answers and len(answers_ids) > 1:
|
||||||
|
@ -93,31 +106,39 @@ def survey(request, survey_id):
|
||||||
continue
|
continue
|
||||||
answer_id = int(answer_id)
|
answer_id = int(answer_id)
|
||||||
answer = SurveyQuestionAnswer.objects.get(
|
answer = SurveyQuestionAnswer.objects.get(
|
||||||
id = answer_id,
|
id=answer_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):
|
||||||
all_choices = []
|
all_choices = []
|
||||||
for option_id, choices_ids in form.choices():
|
for option_id, choices_ids in form.choices():
|
||||||
option = get_object_or_404(EventOption, id = option_id,
|
option = get_object_or_404(EventOption, id=option_id,
|
||||||
event = event)
|
event=event)
|
||||||
if type(choices_ids) != list:
|
if type(choices_ids) != list:
|
||||||
choices_ids = [choices_ids]
|
choices_ids = [choices_ids]
|
||||||
if not option.multi_choices and len(choices_ids) > 1:
|
if not option.multi_choices and len(choices_ids) > 1:
|
||||||
|
@ -127,43 +148,52 @@ def get_event_form_choices(event, form):
|
||||||
continue
|
continue
|
||||||
choice_id = int(choice_id)
|
choice_id = int(choice_id)
|
||||||
choice = EventOptionChoice.objects.get(
|
choice = EventOptionChoice.objects.get(
|
||||||
id = choice_id,
|
id=choice_id,
|
||||||
event_option = option)
|
event_option=option)
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def event(request, event_id):
|
def event(request, event_id):
|
||||||
event = get_object_or_404(Event, id = event_id)
|
event = get_object_or_404(Event, id=event_id)
|
||||||
if not event.registration_open:
|
if not event.registration_open:
|
||||||
raise Http404
|
raise Http404
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
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()
|
||||||
|
@ -173,29 +203,34 @@ 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)
|
||||||
registrations_query = EventRegistration.objects.filter(event = event)
|
registrations_query = EventRegistration.objects.filter(event=event)
|
||||||
post_data = clean_post_for_status(request.POST)
|
post_data = clean_post_for_status(request.POST)
|
||||||
form = EventStatusFilterForm(post_data or None, event = event)
|
form = EventStatusFilterForm(post_data or None, event=event)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
for option_id, choice_id, value in form.filters():
|
for option_id, choice_id, value in form.filters():
|
||||||
if option_id == "has_paid":
|
if option_id == "has_paid":
|
||||||
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 = {}
|
||||||
for option in options:
|
for option in options:
|
||||||
for choice in option.choices.all():
|
for choice in option.choices.all():
|
||||||
|
@ -203,25 +238,32 @@ 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
|
||||||
def survey_status(request, survey_id):
|
def survey_status(request, survey_id):
|
||||||
survey = get_object_or_404(Survey, id = survey_id)
|
survey = get_object_or_404(Survey, id=survey_id)
|
||||||
answers_query = SurveyAnswer.objects.filter(survey = survey)
|
answers_query = SurveyAnswer.objects.filter(survey=survey)
|
||||||
post_data = clean_post_for_status(request.POST)
|
post_data = clean_post_for_status(request.POST)
|
||||||
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 = {}
|
||||||
for question in questions:
|
for question in questions:
|
||||||
for answer in question.answers.all():
|
for answer in question.answers.all():
|
||||||
|
@ -229,31 +271,37 @@ 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
|
||||||
def profile(request):
|
def profile(request):
|
||||||
success = False
|
success = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = UserProfileForm(request.POST, instance = request.user.profile)
|
form = UserProfileForm(request.POST, instance=request.user.profile)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
success = True
|
success = True
|
||||||
else:
|
else:
|
||||||
form = UserProfileForm(instance = request.user.profile)
|
form = UserProfileForm(instance=request.user.profile)
|
||||||
return render(request, "profile.html", {"form": form, "success": success})
|
return render(request, "profile.html", {"form": form, "success": success})
|
||||||
|
|
||||||
|
|
||||||
def registration_set_ro_fields(user_form, profile_form):
|
def registration_set_ro_fields(user_form, profile_form):
|
||||||
user_form.fields['username'].widget.attrs['readonly'] = True
|
user_form.fields['username'].widget.attrs['readonly'] = True
|
||||||
profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration_form(request, login_clipper = None, username = None):
|
def registration_form(request, login_clipper=None, username=None):
|
||||||
member = None
|
member = None
|
||||||
if login_clipper:
|
if login_clipper:
|
||||||
clipper = get_object_or_404(Clipper, username = login_clipper)
|
clipper = get_object_or_404(Clipper, username=login_clipper)
|
||||||
try: # check if the given user is already registered
|
try: # check if the given user is already registered
|
||||||
member = User.objects.filter(username = login_clipper).get()
|
member = User.objects.filter(username=login_clipper).get()
|
||||||
username = member.username
|
username = member.username
|
||||||
login_clipper = None
|
login_clipper = None
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
|
@ -261,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(" ")
|
||||||
|
@ -270,35 +319,39 @@ def registration_form(request, login_clipper = None, username = None):
|
||||||
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
if username:
|
if username:
|
||||||
member = get_object_or_404(User, username = username)
|
member = get_object_or_404(User, username=username)
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user = member)
|
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
||||||
# already existing, prefill
|
# already existing, prefill
|
||||||
user_form = RegistrationUserForm(instance = member)
|
user_form = RegistrationUserForm(instance=member)
|
||||||
profile_form = RegistrationProfileForm(instance = profile)
|
profile_form = RegistrationProfileForm(instance=profile)
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
elif not login_clipper:
|
elif not login_clipper:
|
||||||
# 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):
|
||||||
events = Event.objects.filter(old = False).all()
|
events = Event.objects.filter(old=False).all()
|
||||||
member = None
|
member = None
|
||||||
if login_clipper:
|
if login_clipper:
|
||||||
clipper = get_object_or_404(Clipper, username = login_clipper)
|
clipper = get_object_or_404(Clipper, username=login_clipper)
|
||||||
try: # check if the given user is already registered
|
try: # check if the given user is already registered
|
||||||
member = User.objects.filter(username = login_clipper).get()
|
member = User.objects.filter(username=login_clipper).get()
|
||||||
username = member.username
|
username = member.username
|
||||||
login_clipper = None
|
login_clipper = None
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
# new user, but prefill
|
# new user, but prefill
|
||||||
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]
|
||||||
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(" ")
|
||||||
|
@ -307,26 +360,34 @@ def registration_form2(request, login_clipper = None, username = None):
|
||||||
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
user_form.fields['last_name'].initial = " ".join(bits[1:])
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
if username:
|
if username:
|
||||||
member = get_object_or_404(User, username = username)
|
member = get_object_or_404(User, username=username)
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user = member)
|
(profile, _) = CofProfile.objects.get_or_create(user=member)
|
||||||
# already existing, prefill
|
# already existing, prefill
|
||||||
user_form = RegistrationUserForm(instance = member)
|
user_form = RegistrationUserForm(instance=member)
|
||||||
profile_form = RegistrationProfileForm(instance = profile)
|
profile_form = RegistrationProfileForm(instance=profile)
|
||||||
registration_set_ro_fields(user_form, profile_form)
|
registration_set_ro_fields(user_form, profile_form)
|
||||||
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)
|
||||||
elif not login_clipper:
|
elif not login_clipper:
|
||||||
# new user
|
# new user
|
||||||
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
|
||||||
def registration(request):
|
def registration(request):
|
||||||
|
@ -337,113 +398,144 @@ def registration(request):
|
||||||
success = False
|
success = False
|
||||||
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: event_form.is_valid()
|
for event_form in event_forms:
|
||||||
|
event_form.is_valid()
|
||||||
member = None
|
member = None
|
||||||
login_clipper = None
|
login_clipper = None
|
||||||
if "user_exists" in request_dict and request_dict["user_exists"]:
|
if "user_exists" in request_dict and request_dict["user_exists"]:
|
||||||
username = request_dict["username"]
|
username = request_dict["username"]
|
||||||
try:
|
try:
|
||||||
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()
|
||||||
login_clipper = clipper.username
|
login_clipper = clipper.username
|
||||||
except Clipper.DoesNotExist:
|
except Clipper.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
for form in event_forms:
|
for form in event_forms:
|
||||||
if not form.is_valid(): break
|
if not form.is_valid():
|
||||||
if form.cleaned_data['status'] == 'no': continue
|
break
|
||||||
|
if form.cleaned_data['status'] == 'no':
|
||||||
|
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)
|
||||||
if profile.is_cof and not was_cof:
|
if profile.is_cof and not was_cof:
|
||||||
send_custom_mail(member, "bienvenue")
|
send_custom_mail(member, "bienvenue")
|
||||||
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")
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_members(request):
|
def export_members(request):
|
||||||
response = HttpResponse(content_type = 'text/csv')
|
response = HttpResponse(content_type='text/csv')
|
||||||
response['Content-Disposition'] = 'attachment; filename=membres_cof.csv'
|
response['Content-Disposition'] = 'attachment; filename=membres_cof.csv'
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def csv_export_mega(filename, qs):
|
def csv_export_mega(filename, qs):
|
||||||
response = HttpResponse(content_type = 'text/csv')
|
response = HttpResponse(content_type='text/csv')
|
||||||
response['Content-Disposition'] = 'attachment; filename=' + filename
|
response['Content-Disposition'] = 'attachment; filename=' + filename
|
||||||
writer = unicodecsv.writer(response)
|
writer = unicodecsv.writer(response)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega_remarksonly(request):
|
def export_mega_remarksonly(request):
|
||||||
filename = 'remarques_mega_2015.csv'
|
filename = 'remarques_mega_2015.csv'
|
||||||
response = HttpResponse(content_type = 'text/csv')
|
response = HttpResponse(content_type='text/csv')
|
||||||
response['Content-Disposition'] = 'attachment; filename=' + filename
|
response['Content-Disposition'] = 'attachment; filename=' + filename
|
||||||
writer = unicodecsv.writer(response)
|
writer = unicodecsv.writer(response)
|
||||||
|
|
||||||
event = Event.objects.get(title = "Mega 15")
|
event = Event.objects.get(title="Mega 15")
|
||||||
commentfield = event.commentfields.get(name = "Commentaires")
|
commentfield = event.commentfields.get(name="Commentaires")
|
||||||
for val in commentfield.values.all():
|
for val in commentfield.values.all():
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega_bytype(request, type):
|
def export_mega_bytype(request, type):
|
||||||
types = {"orga-actif": "Orga élève",
|
types = {"orga-actif": "Orga élève",
|
||||||
|
@ -454,60 +546,75 @@ def export_mega_bytype(request, type):
|
||||||
if type not in types:
|
if type not in types:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega_orgas(request):
|
def export_mega_orgas(request):
|
||||||
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_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)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega_participants(request):
|
def export_mega_participants(request):
|
||||||
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_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)
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def utile_cof(request):
|
def utile_cof(request):
|
||||||
return render(request, "utile_cof.html", {})
|
return render(request, "utile_cof.html", {})
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def utile_bda(request):
|
def utile_bda(request):
|
||||||
tirages = Tirage.objects.all()
|
tirages = Tirage.objects.all()
|
||||||
return render(request, "utile_bda.html", {'tirages': tirages})
|
return render(request, "utile_bda.html", {'tirages': tirages})
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
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})
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -22,7 +22,7 @@ if __name__ == "__main__":
|
||||||
clipper.save()
|
clipper.save()
|
||||||
print "Updated", username
|
print "Updated", username
|
||||||
else:
|
else:
|
||||||
clipper = Clipper(username = username, fullname = fullname)
|
clipper = Clipper(username=username, fullname=fullname)
|
||||||
clipper.save()
|
clipper.save()
|
||||||
print "Created", username
|
print "Created", username
|
||||||
print "[ DONE ]"
|
print "[ DONE ]"
|
||||||
|
|
|
@ -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:"
|
||||||
|
|
Loading…
Reference in a new issue