Merge branch 'master' into Kerl/test_db

This commit is contained in:
Martin Pépin 2016-07-08 20:06:05 +02:00
commit 00f2ef3b28
17 changed files with 268 additions and 97 deletions

View file

@ -162,3 +162,10 @@ Pour mettre à jour les paquets Python, utiliser la commande suivante :
Pour mettre à jour les modèles après une migration, il faut ensuite faire : Pour mettre à jour les modèles après une migration, il faut ensuite faire :
python manage.py migrate python manage.py migrate
## Documentation utilisateur
Une brève documentation utilisateur pour se faliliariser plus vite avec l'outil
est accessible sur le
[wiki](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/home).

View file

@ -5,6 +5,7 @@ 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 datetime import timedelta from datetime import timedelta
@ -16,7 +17,6 @@ class AttributionInline(admin.TabularInline):
model = Attribution model = Attribution
class ParticipantAdmin(admin.ModelAdmin): class ParticipantAdmin(admin.ModelAdmin):
#inlines = [ChoixSpectacleInline]
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'),
@ -31,8 +31,9 @@ class ParticipantAdmin(admin.ModelAdmin):
else: return u"0 €" 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",
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
@ -107,6 +108,16 @@ Le Bureau des Arts
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):
def clean(self):
cleaned_data=super(AttributionAdminForm, self).clean()
participant = cleaned_data.get("participant")
spectacle = cleaned_data.get("spectacle")
if participant and spectacle:
if participant.tirage != spectacle.tirage:
raise forms.ValidationError(u"Erreur : le participant et le spectacle n'appartiennent pas au même tirage")
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
@ -114,18 +125,21 @@ class AttributionAdmin(admin.ModelAdmin):
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
import autocomplete_light 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=[])
list_display = ("participant", "spectacle", "priority", "double_choice") def tirage(self, obj):
list_filter = ("double_choice",) return obj.participant.tirage
list_display = ("participant", "tirage", "spectacle", "priority", "double_choice")
list_filter = ("double_choice", "participant__tirage")
search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name') search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
class SpectacleAdmin(admin.ModelAdmin): class SpectacleAdmin(admin.ModelAdmin):
model = Spectacle model = Spectacle
list_display = ("title", "date", "location", "slots", "price") list_display = ("title", "date", "tirage", "location", "slots", "price")
list_filter = ("location",) list_filter = ("location", "tirage",)
search_fields = ("title", "location__name") search_fields = ("title", "location__name")
class TirageAdmin(admin.ModelAdmin): class TirageAdmin(admin.ModelAdmin):

View file

@ -0,0 +1,61 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>{{ spectacle }}</h2>
<h3><a href="{% url "admin:bda_attribution_add" %}?spectacle={{spectacle.id}}">Ajouter une attribution</a></h3>
<table class='etat-bda' align="center">
<thead>
<tr>
<th>Nom</th>
<th>Identifiant</th>
<th>Places</th>
<th>Adresse Mail</th>
<th>Payé</th>
<th>Donné</th>
</tr>
</thead>
{% for participant in participants %}
<tr>
<td>{{participant.name}}</td>
<td>{{participant.username}}</td>
<td>{{participant.nb_places}} place{{participant.nb_places|pluralize}}</td>
<td>{{participant.email}}</td>
<td>
<div class={%if participant.paid %}"greenratio"{%else%}"redratio"{%endif%}>
{% if participant.paid %}Oui{% else %}Non{%endif%}
</div>
</td>
<td align="center">
<div class={%if participant.given == participant.nb_places %}"greenratio"
{%elif participant.given == 0%}"redratio"
{%else%}"orangeratio"
{%endif%}>
{% if participant.given == participant.nb_places %}Oui
{% elif participant.given == 0 %}Non
{% else %}{{participant.given}}/{{participant.nb_places}}
{%endif%}
</div>
</td>
</tr>
{% endfor %}
</table>
<br>
<button type="button" onclick="toggle('export-mails')">Afficher/Cacher mails participants</button>
<pre id="export-mails" style="display:none">
{%for participant in participants %}{{participant.email}}, {%endfor%}
</pre>
<br>
<button type="button" onclick="toggle('export-salle')">Afficher/Cacher liste noms</button>
<pre id="export-salle" style="display:none">
{% for participant in participants %}{{participant.name}} : {{participant.nb_places}} places
{% endfor %}
</pre>
<script>
function toggle(id) {
var pre = document.getElementById(id) ;
pre.style.display = pre.style.display == "none" ? "block" : "none" ;
}
</script>
{% endblock %}

View file

@ -4,4 +4,5 @@
<h2>Impayés</h2> <h2>Impayés</h2>
<textarea style="width: 100%; height: 100px; margin-top: 10px;"> <textarea style="width: 100%; height: 100px; margin-top: 10px;">
{% for participant in unpaid %}{{ participant.user.email }}, {% endfor %}</textarea> {% for participant in unpaid %}{{ participant.user.email }}, {% endfor %}</textarea>
<h3>Total&nbsp: {{ unpaid|length }}</h3>
{% endblock %} {% endblock %}

View file

@ -1,11 +1,16 @@
{% extends "base_title.html" %} {% extends "base_title.html" %}
{% block realcontent %} {% block realcontent %}
<h1><strong>Spectacles</strong></h1> <h2><strong>{{tirage_name}}</strong></h2>
<h3>Liste des spectacles</h3>
<ul> <ul>
<li><a href="{% url 'bda-unpaid' tirage_id %}">Pas payé</a></li>
{% for spectacle in object_list %} {% for spectacle in object_list %}
<li><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle }}</a></li> <li><a href="{% url 'bda-spectacle' tirage_id spectacle.id %}">{{ spectacle }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
<h3> Exports </h3>
<ul>
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
<li><a href="{% url 'bda-liste-spectacles-ics' tirage_id %}">Calendrier des spectacles (.ics)</a>
</ul>
{% endblock %} {% endblock %}

View file

@ -5,6 +5,7 @@ from __future__ import division
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db import models from django.db import models
from django.db.models import Count
from django.core import serializers from django.core import serializers
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
import hashlib import hashlib
@ -237,7 +238,9 @@ def do_tirage(request, tirage_id):
# FIXME: Établir les conditions de validations (formulaire ?) # FIXME: Établir les conditions de validations (formulaire ?)
# cf. issue #32 # cf. issue #32
if False: if False:
Attribution.objects.all().delete() Attribution.objects.filter(
spectacle__tirage=tirage_elt
).delete()
for (show, members, _) in results: for (show, members, _) in results:
for (member, _, _, _) in members: for (member, _, _, _) in members:
attrib = Attribution(spectacle=show, participant=member) attrib = Attribution(spectacle=show, participant=member)
@ -291,9 +294,28 @@ def revente(request, tirage_id):
@buro_required @buro_required
def spectacle(request, tirage_id, spectacle_id): def spectacle(request, tirage_id, spectacle_id):
tirage = get_object_or_404(Tirage, id=tirage_id) tirage = get_object_or_404(Tirage, id=tirage_id)
spectacle = get_object_or_404(Spectacle, id = spectacle_id, tirage=tirage) spectacle = get_object_or_404(Spectacle, id=spectacle_id, tirage=tirage)
return render(request, "bda-emails.html", {"spectacle": spectacle}) attributions = spectacle.attribues.all()
participants = {}
for attrib in attributions:
participant = attrib.participant
participant_info = {'lastname': participant.user.last_name,
'name': participant.user.get_full_name,
'username': participant.user.username,
'email': participant.user.email,
'given': int(attrib.given),
'paid': participant.paid,
'nb_places': 1}
if participant.id in participants:
participants[participant.id]['nb_places'] += 1
participants[participant.id]['given'] += attrib.given
else:
participants[participant.id] = participant_info
participants_info = sorted(participants.values(),
key=lambda part: part['lastname'])
return render(request, "bda-participants.html",
{"spectacle": spectacle, "participants": participants_info})
class SpectacleListView(ListView): class SpectacleListView(ListView):
model = Spectacle model = Spectacle
@ -305,12 +327,15 @@ class SpectacleListView(ListView):
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
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.filter(paid=False).all() unpaid = tirage.participant_set \
.annotate(nb_attributions=Count('attribution')) \
.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

View file

@ -53,6 +53,7 @@ urlpatterns = patterns('',
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/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',

View file

@ -9,7 +9,7 @@ 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): 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):
@ -30,7 +30,8 @@ def add_link_field(target_model = '', field = '', link_text = unicode, desc_text
class SurveyQuestionAnswerInline(admin.TabularInline): class SurveyQuestionAnswerInline(admin.TabularInline):
model = SurveyQuestionAnswer model = SurveyQuestionAnswer
@add_link_field(desc_text = lambda x: "Réponses", link_text = lambda x: "Éditer les réponses") @add_link_field(desc_text=lambda x: "Réponses",
link_text=lambda x: "Éditer les réponses")
class SurveyQuestionInline(admin.TabularInline): class SurveyQuestionInline(admin.TabularInline):
model = SurveyQuestion model = SurveyQuestion
@ -47,7 +48,8 @@ class SurveyAdmin(admin.ModelAdmin):
class EventOptionChoiceInline(admin.TabularInline): class EventOptionChoiceInline(admin.TabularInline):
model = EventOptionChoice model = EventOptionChoice
@add_link_field(desc_text = lambda x: "Choix", link_text = lambda x: "Éditer les choix") @add_link_field(desc_text=lambda x: "Choix",
link_text=lambda x: "Éditer les choix")
class EventOptionInline(admin.TabularInline): class EventOptionInline(admin.TabularInline):
model = EventOption model = EventOption
@ -67,7 +69,6 @@ class EventAdmin(admin.ModelAdmin):
class CofProfileInline(admin.StackedInline): class CofProfileInline(admin.StackedInline):
model = CofProfile model = CofProfile
#form = BaseDynamicEntityForm
inline_classes = ("collapse open",) inline_classes = ("collapse open",)
class FkeyLookup(object): class FkeyLookup(object):
@ -80,14 +81,15 @@ class FkeyLookup(object):
def __get__(self, obj, klass): def __get__(self, obj, klass):
if obj is None: if obj is None:
return self # hack required to make Django validate (if obj is None, then we're a class, and classes are callable <wink>) return self # hack required to make Django validate (if obj is
# None, then we're a class, and classes are callable
# <wink>)
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:
return getattr(self.profile, field) return getattr(self.profile, field)
@ -121,9 +123,14 @@ class UserProfileAdmin(UserAdmin):
return False return False
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 + ('profile_login_clipper','profile_phone','profile_occupation','profile_mailing_cof','profile_mailing_bda','profile_mailing_bda_revente','is_cof','is_buro',) list_display = ('profile_num',) + UserAdmin.list_display \
+ ( 'profile_login_clipper','profile_phone','profile_occupation',
'profile_mailing_cof','profile_mailing_bda',
'profile_mailing_bda_revente','is_cof','is_buro',)
list_display_links = ('username','email','first_name','last_name') list_display_links = ('username','email','first_name','last_name')
list_filter = UserAdmin.list_filter + ('profile__is_cof', 'profile__is_buro', 'profile__mailing_cof', 'profile__mailing_bda') list_filter = UserAdmin.list_filter \
+ ( 'profile__is_cof', 'profile__is_buro', 'profile__mailing_cof',
'profile__mailing_bda')
search_fields = UserAdmin.search_fields + ('profile__phone',) search_fields = UserAdmin.search_fields + ('profile__phone',)
inlines = [ inlines = [
CofProfileInline, CofProfileInline,
@ -140,11 +147,13 @@ 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', 'user__email', 'event__title') search_fields = ('user__username', 'user__first_name', 'user__last_name',
'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', 'user__email', 'matiere__name', 'niveau') search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name', 'niveau')
list_filter = ('matiere','niveau','agrege') list_filter = ('matiere','niveau','agrege')
class PetitCoursAttributionAdmin(admin.ModelAdmin): class PetitCoursAttributionAdmin(admin.ModelAdmin):
@ -153,10 +162,18 @@ class PetitCoursAttributionAdmin(admin.ModelAdmin):
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', 'user__email', 'matiere__name') search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'matiere__name')
actions = ['reset',]
actions_on_bottom = True
def reset(self, request, queryset):
queryset.update(count=0)
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','traitee','processed') list_display = ('name','email','agrege_requis','niveau','created',
'traitee','processed')
list_filter = ('traitee','niveau') list_filter = ('traitee','niveau')
admin.site.register(Survey, SurveyAdmin) admin.site.register(Survey, SurveyAdmin)

View file

@ -79,6 +79,11 @@ class SurveyForm(forms.Form):
field.question_id = question.id field.question_id = question.id
self.fields["question_%d" % question.id] = field self.fields["question_%d" % question.id] = field
def answers(self):
for name, value in self.cleaned_data.items():
if name.startswith('question_'):
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")

View 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', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='petitcoursdemande',
name='processed',
field=models.DateTimeField(null=True, verbose_name='Date de traitement', blank=True),
),
]

View file

@ -17,9 +17,9 @@ LEVELS_CHOICES = (
) )
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",
through = "PetitCoursAbility") through="PetitCoursAbility")
class Meta: class Meta:
verbose_name = "Matière de petits cours" verbose_name = "Matière de petits cours"
@ -30,11 +30,11 @@ class PetitCoursSubject(models.Model):
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:
verbose_name = "Compétence petits cours" verbose_name = "Compétence petits cours"
@ -44,27 +44,41 @@ class PetitCoursAbility(models.Model):
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)
email = models.CharField(_(u"Adresse email"), max_length = 300) email = models.CharField(_(u"Adresse email"), max_length=300)
phone = models.CharField(_(u"Téléphone (facultatif)"), max_length = 20, blank = True) phone = models.CharField(_(u"Téléphone (facultatif)"),
quand = models.CharField(_(u"Quand ?"), help_text = _(u"Indiquez ici la période désirée pour les petits cours (vacances scolaires, semaine, week-end)."), max_length = 300, blank = True) max_length=20, blank=True)
freq = models.CharField(_(u"Fréquence"), help_text = _(u"Indiquez ici la fréquence envisagée (hebdomadaire, 2 fois par semaine, ...)"), max_length = 300, blank = True) quand = models.CharField(
lieu = models.CharField(_(u"Lieu (si préférence)"), help_text = _(u"Si vous avez avez une préférence sur le lieu."), max_length = 300, blank = True) _(u"Quand ?"),
help_text=_(u"Indiquez ici la période désirée pour les petits" \
+ " cours (vacances scolaires, semaine, week-end)."),
max_length=300, blank=True)
freq = models.CharField(
_(u"Fréquence"),
help_text=_(u"Indiquez ici la fréquence envisagée " \
+ "(hebdomadaire, 2 fois par semaine, ...)"),
max_length=300, blank=True)
lieu = models.CharField(
_(u"Lieu (si préférence)"),
help_text=_(u"Si vous avez avez une préférence sur le lieu."),
max_length=300, blank=True)
matieres = models.ManyToManyField(PetitCoursSubject, verbose_name = _(u"Matières"), matieres = models.ManyToManyField(
related_name = "demandes") PetitCoursSubject, verbose_name=_(u"Matières"),
agrege_requis = models.BooleanField(_(u"Agrégé requis"), default = False) related_name="demandes")
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)
traitee = models.BooleanField(_(u"Traitée"), default = False) traitee = models.BooleanField(_(u"Traitée"), default=False)
traitee_par = models.ForeignKey(User, blank = True, null = True) traitee_par = models.ForeignKey(User, blank=True, null=True)
processed = models.DateTimeField(_(u"Date de traitement"), blank = True) processed = models.DateTimeField(_(u"Date de traitement"),
created = models.DateTimeField(_(u"Date de création"), auto_now_add = True) blank=True, null=True)
created = models.DateTimeField(_(u"Date de création"), auto_now_add=True)
class Meta: class Meta:
verbose_name = "Demande de petits cours" verbose_name = "Demande de petits cours"
@ -75,27 +89,31 @@ class PetitCoursDemande(models.Model):
class PetitCoursAttribution(models.Model): class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
demande = models.ForeignKey(PetitCoursDemande, verbose_name = _("Demande")) demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande"))
matiere = models.ForeignKey(PetitCoursSubject, verbose_name = _(u"Matière")) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_(u"Matière"))
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"), default = False) selected = models.BooleanField(_(u"Sélectionné par le demandeur"),
default=False)
class Meta: class Meta:
verbose_name = "Attribution de petits cours" verbose_name = "Attribution de petits cours"
verbose_name_plural = "Attributions de petits cours" verbose_name_plural = "Attributions de petits cours"
def __unicode__(self): def __unicode__(self):
return u"Attribution de la demande %d à %s pour %s" % (self.demande.id, self.user.username, self.matiere) return u"Attribution de la demande %d à %s pour %s" \
% (self.demande.id, self.user.username, self.matiere)
class PetitCoursAttributionCounter(models.Model): class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
matiere = models.ForeignKey(PetitCoursSubject, verbose_name = _("Matiere")) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere"))
count = models.IntegerField("Nombre d'envois", default = 0) count = models.IntegerField("Nombre d'envois", default=0)
class Meta: class Meta:
verbose_name = "Compteur d'attribution de petits cours" verbose_name = "Compteur d'attribution de petits cours"
verbose_name_plural = "Compteurs d'attributions de petits cours" verbose_name_plural = "Compteurs d'attributions de petits cours"
def __unicode__(self): def __unicode__(self):
return u"%d demandes envoyées à %s pour %s" % (self.count, self.user.username, self.matiere) return u"%d demandes envoyées à %s pour %s" \
% (self.count, self.user.username, self.matiere)

View file

@ -63,9 +63,21 @@
<li><a href="{% url "gestioncof.views.survey_status" survey.id %}">Sondage : {{ survey.title }}</a></li> <li><a href="{% url "gestioncof.views.survey_status" survey.id %}">Sondage : {{ survey.title }}</a></li>
{% endfor %} {% endfor %}
<br> <br>
<li><a href="{% url "gestioncof.views.utile_cof" %}">Liens utiles du COF</a></li> </ul>
<li><a href="{% url "gestioncof.views.utile_bda" %}">Liens utiles BdA</a></li> <h3>Gestion tirages BDA</h3>
</ul> <ul>
{% for tirage in open_tirages %}
<h4>{{ tirage.title }}</h4>
<li><a href="{% url "bda-liste-spectacles" tirage.id %}">Spectacles</a></li>
<li><a href="{% url "admin:bda_participant_changelist" %}?tirage__id__exact={{ tirage.id }}">Participants</a></li>
{% endfor %}
</ul>
<h3>Liens utiles</h3>
<ul>
<li><a href="{% url "gestioncof.views.utile_cof" %}">Liens utiles du COF</a></li>
<li><a href="{% url "gestioncof.views.utile_bda" %}">Liens utiles BdA</a></li>
</ul>
{% endif %} {% endif %}
<h3>Pour tout problème : cof@ens.fr.</h3> <h3>Pour tout problème : cof@ens.fr.</h3>

View file

@ -20,7 +20,7 @@
<td>{% for matiere in demande.matieres.all %}{% if forloop.counter0 > 0 %}, {% endif %}{{ matiere }}{% endfor %}</td> <td>{% for matiere in demande.matieres.all %}{% if forloop.counter0 > 0 %}, {% endif %}{{ matiere }}{% endfor %}</td>
<td>{{ demande.created|date:"d E Y" }}</td> <td>{{ demande.created|date:"d E Y" }}</td>
<td style="text-align: center;"><img src="{% if demande.traitee %}{% static "images/yes.png" %}{% else %}{% static "images/no.png" %}{% endif %}" /></td> <td style="text-align: center;"><img src="{% if demande.traitee %}{% static "images/yes.png" %}{% else %}{% static "images/no.png" %}{% endif %}" /></td>
<td>{% if demande.traitee_par %}{{ demande.traitee_par.username }}{% else %}<img src="{% static "/images/none.png" %}" />{% endif %}</td> <td>{% if demande.traitee_par %}{{ demande.traitee_par.username }}{% else %}<img src="{% static "images/none.png" %}" />{% endif %}</td>
<td><a href="{% url "petits-cours-demande-details" demande.id %}" class="see_detail">Détails</a></td> <td><a href="{% url "petits-cours-demande-details" demande.id %}" class="see_detail">Détails</a></td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -10,14 +10,4 @@
<li><a href="{% url 'gestioncof.views.liste_bdadiff' %}">BdA diffusion</a></li> <li><a href="{% url 'gestioncof.views.liste_bdadiff' %}">BdA diffusion</a></li>
<li><a href="{% url 'gestioncof.views.liste_bdarevente' %}">BdA revente</a></li> <li><a href="{% url 'gestioncof.views.liste_bdarevente' %}">BdA revente</a></li>
</ul> </ul>
<h3>Tirages</h3>
{% for tirage in tirages %}
<h4>{{ tirage.title }}</h4>
<ul>
<li><a href="{% url 'bda.views.etat_places' tirage.id %}">Etat des voeux</a></li>
<li><a href="{% url 'bda-liste-spectacles' tirage.id %}">Mailing list par spectacle</a></li>
<li><a href="{% url 'bda.views.unpaid' tirage.id %}">Mailing list des impayés</a></li>
<li><a href="{% url 'bda-liste-spectacles-ics' tirage.id %}">Calendrier des spectacles (.ics)</a></li>
</ul>
{% endfor %}
{% endblock %} {% endblock %}

View file

@ -34,3 +34,4 @@ def highlight_clipper(clipper, q):
else: else:
text = clipper.username text = clipper.username
return highlight_text(text, q) return highlight_text(text, q)

View file

@ -2,41 +2,41 @@ from django.conf.urls import url
from gestioncof.petits_cours_views import DemandeListView from gestioncof.petits_cours_views import DemandeListView
export_patterns = [ export_patterns = [
url(r'members$', 'gestioncof.views.export_members'), url(r'^members$', 'gestioncof.views.export_members'),
url(r'mega/avecremarques$', 'gestioncof.views.export_mega_remarksonly'), url(r'^mega/avecremarques$', 'gestioncof.views.export_mega_remarksonly'),
url(r'mega/participants$', 'gestioncof.views.export_mega_participants'), url(r'^mega/participants$', 'gestioncof.views.export_mega_participants'),
url(r'mega/orgas$', 'gestioncof.views.export_mega_orgas'), url(r'^mega/orgas$', 'gestioncof.views.export_mega_orgas'),
url(r'mega/(?P<type>.+)$', 'gestioncof.views.export_mega_bytype'), url(r'^mega/(?P<type>.+)$', 'gestioncof.views.export_mega_bytype'),
url(r'mega$', 'gestioncof.views.export_mega'), url(r'^mega$', 'gestioncof.views.export_mega'),
] ]
petitcours_patterns = [ petitcours_patterns = [
url(r'inscription$', 'gestioncof.petits_cours_views.inscription', url(r'^inscription$', 'gestioncof.petits_cours_views.inscription',
name='petits-cours-inscription'), name='petits-cours-inscription'),
url(r'demande$', 'gestioncof.petits_cours_views.demande', url(r'^demande$', 'gestioncof.petits_cours_views.demande',
name='petits-cours-demande'), name='petits-cours-demande'),
url(r'demande-raw$', 'gestioncof.petits_cours_views.demande_raw', url(r'^demande-raw$', 'gestioncof.petits_cours_views.demande_raw',
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',
name='petits-cours-demande-traitement'), name='petits-cours-demande-traitement'),
url(r'demandes/(?P<demande_id>\d+)/retraitement$', url(r'^demandes/(?P<demande_id>\d+)/retraitement$',
'gestioncof.petits_cours_views.retraitement', 'gestioncof.petits_cours_views.retraitement',
name='petits-cours-demande-retraitement'), name='petits-cours-demande-retraitement'),
] ]
surveys_patterns = [ surveys_patterns = [
url(r'^survey/(?P<survey_id>\d+)/status$', 'gestioncof.views.survey_status'), url(r'^(?P<survey_id>\d+)/status$', 'gestioncof.views.survey_status'),
url(r'^survey/(?P<survey_id>\d+)$', 'gestioncof.views.survey'), url(r'^(?P<survey_id>\d+)$', 'gestioncof.views.survey'),
] ]
events_patterns = [ events_patterns = [
url(r'^event/(?P<event_id>\d+)$', 'gestioncof.views.event'), url(r'^(?P<event_id>\d+)$', 'gestioncof.views.event'),
url(r'^event/(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'), url(r'^(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'),
] ]

View file

@ -59,11 +59,6 @@ def logout(request):
else: else:
return redirect("django.contrib.auth.views.logout") return redirect("django.contrib.auth.views.logout")
def answers(self):
for name, value in self.cleaned_data.items():
if name.startswith('question_'):
yield (self.fields[name].question_id, value)
@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)
@ -408,7 +403,7 @@ 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.UnicodeWriter(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]
@ -420,7 +415,7 @@ def export_members(request):
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.UnicodeWriter(response) writer = unicodecsv.writer(response)
for reg in qs.all(): for reg in qs.all():
user = reg.user user = reg.user
@ -436,7 +431,7 @@ 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.UnicodeWriter(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")