Merge branch 'supportBDS' of git.eleves.ens.fr:cof-geek/gestioCOF into supportBDS

This commit is contained in:
Qwann 2017-02-23 19:00:58 +01:00
commit 9c6f5533ec
54 changed files with 691 additions and 422 deletions

View file

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import autocomplete_light
from datetime import timedelta from datetime import timedelta
from custommail.shortcuts import send_mass_custom_mail from custommail.shortcuts import send_mass_custom_mail
@ -119,8 +118,6 @@ class AttributionAdmin(admin.ModelAdmin):
class ChoixSpectacleAdmin(admin.ModelAdmin): class ChoixSpectacleAdmin(admin.ModelAdmin):
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", list_display = ("participant", "tirage", "spectacle", "priority",

6
bda/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class BdAConfig(AppConfig):
name = "bda"
verbose_name = "Gestion des tirages du BdA"

View file

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import autocomplete_light
from bda.models import Participant, Spectacle
autocomplete_light.register(
Participant, search_fields=('user__username', 'user__first_name',
'user__last_name'),
autocomplete_js_attributes={'placeholder': 'participant...'})
autocomplete_light.register(
Spectacle, search_fields=('title', ),
autocomplete_js_attributes={'placeholder': 'spectacle...'})

View file

@ -59,7 +59,9 @@ class Migration(migrations.Migration):
('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)), ('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
('slots', models.IntegerField(verbose_name=b'Places')), ('slots', models.IntegerField(verbose_name=b'Places')),
('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')), ('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')),
('location', models.ForeignKey(to='bda.Salle')), ('location', models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Salle')),
], ],
options={ options={
'ordering': ('priority', 'date', 'title'), 'ordering': ('priority', 'date', 'title'),
@ -79,27 +81,39 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='participant', model_name='participant',
name='user', name='user',
field=models.OneToOneField(to=settings.AUTH_USER_MODEL), field=models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='choixspectacle', model_name='choixspectacle',
name='participant', name='participant',
field=models.ForeignKey(to='bda.Participant'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
), ),
migrations.AddField( migrations.AddField(
model_name='choixspectacle', model_name='choixspectacle',
name='spectacle', name='spectacle',
field=models.ForeignKey(related_name='participants', to='bda.Spectacle'), field=models.ForeignKey(
on_delete=models.CASCADE,
related_name='participants',
to='bda.Spectacle'),
), ),
migrations.AddField( migrations.AddField(
model_name='attribution', model_name='attribution',
name='participant', name='participant',
field=models.ForeignKey(to='bda.Participant'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Participant'),
), ),
migrations.AddField( migrations.AddField(
model_name='attribution', model_name='attribution',
name='spectacle', name='spectacle',
field=models.ForeignKey(related_name='attribues', to='bda.Spectacle'), field=models.ForeignKey(
related_name='attribues',
on_delete=models.CASCADE,
to='bda.Spectacle'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='choixspectacle', name='choixspectacle',

View file

@ -39,18 +39,26 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='participant', model_name='participant',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='participant', model_name='participant',
name='tirage', name='tirage',
field=models.ForeignKey(default=1, to='bda.Tirage'), field=models.ForeignKey(
on_delete=models.CASCADE,
default=1,
to='bda.Tirage'),
preserve_default=False, preserve_default=False,
), ),
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
name='tirage', name='tirage',
field=models.ForeignKey(default=1, to='bda.Tirage'), field=models.ForeignKey(
on_delete=models.CASCADE,
default=1,
to='bda.Tirage'),
preserve_default=False, preserve_default=False,
), ),
] ]

View file

@ -72,8 +72,11 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
name='category', name='category',
field=models.ForeignKey(blank=True, to='bda.CategorieSpectacle', field=models.ForeignKey(
null=True), on_delete=models.CASCADE,
blank=True,
to='bda.CategorieSpectacle',
null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='spectacle', model_name='spectacle',
@ -84,6 +87,8 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='quote', model_name='quote',
name='spectacle', name='spectacle',
field=models.ForeignKey(to='bda.Spectacle'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='bda.Spectacle'),
), ),
] ]

View file

@ -46,21 +46,28 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='attribution', name='attribution',
field=models.OneToOneField(to='bda.Attribution', field=models.OneToOneField(
related_name='revente'), to='bda.Attribution',
on_delete=models.CASCADE,
related_name='revente'),
), ),
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='seller', name='seller',
field=models.ForeignKey(to='bda.Participant', field=models.ForeignKey(
verbose_name='Vendeur', on_delete=models.CASCADE,
related_name='original_shows'), to='bda.Participant',
verbose_name='Vendeur',
related_name='original_shows'),
), ),
migrations.AddField( migrations.AddField(
model_name='spectaclerevente', model_name='spectaclerevente',
name='soldTo', name='soldTo',
field=models.ForeignKey(to='bda.Participant', field=models.ForeignKey(
verbose_name='Vendue à', null=True, on_delete=models.CASCADE,
blank=True), to='bda.Participant',
verbose_name='Vendue à',
null=True,
blank=True),
), ),
] ]

View file

@ -46,9 +46,14 @@ class CategorieSpectacle(models.Model):
class Spectacle(models.Model): class Spectacle(models.Model):
title = models.CharField("Titre", max_length=300) title = models.CharField("Titre", max_length=300)
category = models.ForeignKey(CategorieSpectacle, blank=True, null=True) category = models.ForeignKey(
CategorieSpectacle,
on_delete=models.CASCADE,
blank=True,
null=True
)
date = models.DateTimeField("Date & heure") date = models.DateTimeField("Date & heure")
location = models.ForeignKey(Salle) location = models.ForeignKey(Salle, on_delete=models.CASCADE)
vips = models.TextField('Personnalités', blank=True) vips = models.TextField('Personnalités', blank=True)
description = models.TextField("Description", blank=True) description = models.TextField("Description", blank=True)
slots_description = models.TextField("Description des places", blank=True) slots_description = models.TextField("Description des places", blank=True)
@ -58,7 +63,7 @@ class Spectacle(models.Model):
max_length=500) max_length=500)
price = models.FloatField("Prix d'une place") price = models.FloatField("Prix d'une place")
slots = models.IntegerField("Places") slots = models.IntegerField("Places")
tirage = models.ForeignKey(Tirage) tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
listing = models.BooleanField("Les places sont sur listing") listing = models.BooleanField("Les places sont sur listing")
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True, rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
null=True) null=True)
@ -116,7 +121,7 @@ class Spectacle(models.Model):
class Quote(models.Model): class Quote(models.Model):
spectacle = models.ForeignKey(Spectacle) spectacle = models.ForeignKey(Spectacle, on_delete=models.CASCADE)
text = models.TextField('Citation') text = models.TextField('Citation')
author = models.CharField('Auteur', max_length=200) author = models.CharField('Auteur', max_length=200)
@ -130,7 +135,7 @@ PAYMENT_TYPES = (
class Participant(models.Model): class Participant(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User, on_delete=models.CASCADE)
choices = models.ManyToManyField(Spectacle, choices = models.ManyToManyField(Spectacle,
through="ChoixSpectacle", through="ChoixSpectacle",
related_name="chosen_by") related_name="chosen_by")
@ -141,7 +146,7 @@ class Participant(models.Model):
paymenttype = models.CharField("Moyen de paiement", paymenttype = models.CharField("Moyen de paiement",
max_length=6, choices=PAYMENT_TYPES, max_length=6, choices=PAYMENT_TYPES,
blank=True) blank=True)
tirage = models.ForeignKey(Tirage) tirage = models.ForeignKey(Tirage, on_delete=models.CASCADE)
choicesrevente = models.ManyToManyField(Spectacle, choicesrevente = models.ManyToManyField(Spectacle,
related_name="subscribed", related_name="subscribed",
blank=True) blank=True)
@ -157,8 +162,15 @@ DOUBLE_CHOICES = (
class ChoixSpectacle(models.Model): class ChoixSpectacle(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(
spectacle = models.ForeignKey(Spectacle, related_name="participants") Participant,
on_delete=models.CASCADE
)
spectacle = models.ForeignKey(
Spectacle,
on_delete=models.CASCADE,
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, default="1", choices=DOUBLE_CHOICES,
@ -185,8 +197,15 @@ class ChoixSpectacle(models.Model):
class Attribution(models.Model): class Attribution(models.Model):
participant = models.ForeignKey(Participant) participant = models.ForeignKey(
spectacle = models.ForeignKey(Spectacle, related_name="attribues") Participant,
on_delete=models.CASCADE
)
spectacle = models.ForeignKey(
Spectacle,
on_delete=models.CASCADE,
related_name="attribues"
)
given = models.BooleanField("Donnée", default=False) given = models.BooleanField("Donnée", default=False)
def __str__(self): def __str__(self):
@ -195,19 +214,29 @@ class Attribution(models.Model):
class SpectacleRevente(models.Model): class SpectacleRevente(models.Model):
attribution = models.OneToOneField(Attribution, attribution = models.OneToOneField(
related_name="revente") Attribution,
on_delete=models.CASCADE,
related_name="revente"
)
date = models.DateTimeField("Date de mise en vente", date = models.DateTimeField("Date de mise en vente",
default=timezone.now) default=timezone.now)
answered_mail = models.ManyToManyField(Participant, answered_mail = models.ManyToManyField(Participant,
related_name="wanted", related_name="wanted",
blank=True) blank=True)
seller = models.ForeignKey(Participant, seller = models.ForeignKey(
related_name="original_shows", Participant,
verbose_name="Vendeur") on_delete=models.CASCADE,
soldTo = models.ForeignKey(Participant, blank=True, null=True, related_name="original_shows",
verbose_name="Vendue à") verbose_name="Vendeur"
)
soldTo = models.ForeignKey(
Participant,
on_delete=models.CASCADE,
blank=True,
null=True,
verbose_name="Vendue à"
)
notif_sent = models.BooleanField("Notification envoyée", notif_sent = models.BooleanField("Notification envoyée",
default=False) default=False)
tirage_done = models.BooleanField("Tirage effectué", tirage_done = models.BooleanField("Tirage effectué",

View file

@ -16,7 +16,7 @@
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4> <h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
<br/> <br/>
<p>Ne manque pas un spectacle avec le <p>Ne manque pas un spectacle avec le
<a href="{% url "cof.views.calendar" %}">calendrier <a href="{% url "calendar" %}">calendrier
automatique&#8239;!</a></p> automatique&#8239;!</a></p>
{% else %} {% else %}
<h3>Vous n'avez aucune place :(</h3> <h3>Vous n'avez aucune place :(</h3>

6
bds/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class BDSConfig(AppConfig):
name = "bds"
verbose_name = "Application de gestion du BDS"

View file

@ -23,7 +23,10 @@ class Migration(migrations.Migration):
('cotisation_period', models.CharField(choices=[('ANN', 'Année'), ('SE1', 'Premier semestre'), ('SE2', 'Deuxième semestre')], verbose_name='Inscription', max_length=3, default='ANN')), ('cotisation_period', models.CharField(choices=[('ANN', 'Année'), ('SE1', 'Premier semestre'), ('SE2', 'Deuxième semestre')], verbose_name='Inscription', max_length=3, default='ANN')),
('registration_date', models.DateField(verbose_name="Date d'inscription", auto_now_add=True)), ('registration_date', models.DateField(verbose_name="Date d'inscription", auto_now_add=True)),
('payment_method', models.CharField(choices=[('CASH', 'Liquide'), ('BANK', 'Transfer bancaire'), ('CHEQUE', 'Cheque'), ('OTHER', 'Autre')], verbose_name='Methode de paiement', max_length=6, default='CASH')), ('payment_method', models.CharField(choices=[('CASH', 'Liquide'), ('BANK', 'Transfer bancaire'), ('CHEQUE', 'Cheque'), ('OTHER', 'Autre')], verbose_name='Methode de paiement', max_length=6, default='CASH')),
('profile', models.OneToOneField(related_name='bds', to='gestion.Profile')), ('profile', models.OneToOneField(
related_name='bds',
on_delete=models.CASCADE,
to='gestion.Profile')),
], ],
), ),
] ]

View file

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def create_groups(apps, schema_editor):
"""
Creates the groups for BDS members and staff
"""
Group = apps.get_model("auth", "Group")
Group.objects.get_or_create(name="bds_members")
Group.objects.get_or_create(name="bds_buro")
class Migration(migrations.Migration):
dependencies = [
('bds', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='bdsprofile',
options={
'permissions': [
('member', 'Is a BDS member'),
('buro', 'Is part of the BDS staff')
],
'verbose_name': 'Profil BDS',
'verbose_name_plural': 'Profils BDS'
},
),
migrations.RunPython(create_groups, migrations.RunPython.noop),
]

View file

@ -55,3 +55,11 @@ class BdsProfile(models.Model):
default='CASH', default='CASH',
choices=PAYMENT_METHOD_CHOICES, choices=PAYMENT_METHOD_CHOICES,
max_length=6) max_length=6)
class Meta:
verbose_name = "Profil BDS"
verbose_name_plural = "Profils BDS"
permissions = [
("member", "Is a BDS member"),
("buro", "Is part of the BDS staff")
]

View file

@ -1,19 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
import django.utils.six as six import django.utils.six as six
import autocomplete_light
from .petits_cours_models import PetitCoursDemande, \ from .petits_cours_models import PetitCoursDemande, \
PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \ PetitCoursSubject, PetitCoursAbility, PetitCoursAttribution, \
PetitCoursAttributionCounter PetitCoursAttributionCounter
from .models import ( from .models import (
SurveyQuestionAnswer, SurveyQuestion, CofProfile, EventOption, SurveyQuestionAnswer, SurveyQuestion, CofProfile, EventOption,
EventOptionChoice, Event, Club, EventCommentField, EventRegistration, EventOptionChoice, Event, EventCommentField, EventRegistration,
Survey Survey
) )
@ -95,7 +92,6 @@ class EventAdmin(admin.ModelAdmin):
class EventRegistrationAdmin(admin.ModelAdmin): class EventRegistrationAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(EventRegistration, exclude=[])
list_display = ('__unicode__' if six.PY2 else '__str__', 'event', 'user', list_display = ('__unicode__' if six.PY2 else '__str__', 'event', 'user',
'paid') 'paid')
list_filter = ('paid',) list_filter = ('paid',)
@ -135,30 +131,11 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin):
search_fields = ('name', 'email', 'phone', 'lieu', 'remarques') search_fields = ('name', 'email', 'phone', 'lieu', 'remarques')
class ClubAdminForm(forms.ModelForm):
def clean(self):
cleaned_data = super(ClubAdminForm, self).clean()
respos = cleaned_data.get('respos')
members = cleaned_data.get('membres')
for respo in respos.all():
if respo not in members:
raise forms.ValidationError(
"Erreur : le respo %s n'est pas membre du club."
% respo.get_full_name())
return cleaned_data
class ClubAdmin(admin.ModelAdmin):
list_display = ['name']
form = ClubAdminForm
admin.site.register(Survey, SurveyAdmin) admin.site.register(Survey, SurveyAdmin)
admin.site.register(SurveyQuestion, SurveyQuestionAdmin) admin.site.register(SurveyQuestion, SurveyQuestionAdmin)
admin.site.register(Event, EventAdmin) admin.site.register(Event, EventAdmin)
admin.site.register(EventOption, EventOptionAdmin) admin.site.register(EventOption, EventOptionAdmin)
admin.site.register(CofProfile) admin.site.register(CofProfile)
admin.site.register(Club, ClubAdmin)
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)

6
cof/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class COFConfig(AppConfig):
name = "cof"
verbose_name = "Application de gestion du COF"

View file

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
import autocomplete_light
from django.contrib.auth.models import User
autocomplete_light.register(
User, search_fields=('username', 'first_name', 'last_name'),
attrs={'placeholder': 'membre...'}
)

View file

@ -12,8 +12,7 @@ from django.forms.formsets import BaseFormSet, formset_factory
from django.db.models import Max from django.db.models import Max
from django.core.validators import MinLengthValidator from django.core.validators import MinLengthValidator
from .models import CofProfile, EventCommentValue, \ from .models import CofProfile, EventCommentValue, CalendarSubscription
CalendarSubscription, Club
from .widgets import TriStateCheckbox from .widgets import TriStateCheckbox
from gestion.models import Profile from gestion.models import Profile
@ -362,14 +361,3 @@ class CalendarForm(forms.ModelForm):
model = CalendarSubscription model = CalendarSubscription
fields = ['subscribe_to_events', 'subscribe_to_my_shows', fields = ['subscribe_to_events', 'subscribe_to_my_shows',
'other_shows'] 'other_shows']
class ClubsForm(forms.Form):
"""
Formulaire d'inscription d'un membre à plusieurs clubs du COF.
"""
clubs = forms.ModelMultipleChoiceField(
label="Inscriptions aux clubs du COF",
queryset=Club.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False)

View file

@ -48,7 +48,10 @@ class Migration(migrations.Migration):
('is_buro', models.BooleanField(default=False, verbose_name=b'Membre du Bur\xc3\xb4')), ('is_buro', models.BooleanField(default=False, verbose_name=b'Membre du Bur\xc3\xb4')),
('petits_cours_accept', models.BooleanField(default=False, verbose_name=b'Recevoir des petits cours')), ('petits_cours_accept', models.BooleanField(default=False, verbose_name=b'Recevoir des petits cours')),
('petits_cours_remarques', models.TextField(default=b'', verbose_name='Remarques et pr\xe9cisions pour les petits cours', blank=True)), ('petits_cours_remarques', models.TextField(default=b'', verbose_name='Remarques et pr\xe9cisions pour les petits cours', blank=True)),
('user', models.OneToOneField(related_name='profile', to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(
related_name='profile',
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Profil COF', 'verbose_name': 'Profil COF',
@ -91,7 +94,10 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=200, verbose_name=b'Champ')), ('name', models.CharField(max_length=200, verbose_name=b'Champ')),
('fieldtype', models.CharField(default=b'text', max_length=10, verbose_name=b'Type', choices=[(b'text', 'Texte long'), (b'char', 'Texte court')])), ('fieldtype', models.CharField(default=b'text', max_length=10, verbose_name=b'Type', choices=[(b'text', 'Texte long'), (b'char', 'Texte court')])),
('default', models.TextField(verbose_name=b'Valeur par d\xc3\xa9faut', blank=True)), ('default', models.TextField(verbose_name=b'Valeur par d\xc3\xa9faut', blank=True)),
('event', models.ForeignKey(related_name='commentfields', to='cof.Event')), ('event', models.ForeignKey(
related_name='commentfields',
on_delete=models.CASCADE,
to='cof.Event')),
], ],
options={ options={
'verbose_name': 'Champ', 'verbose_name': 'Champ',
@ -102,7 +108,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('content', models.TextField(null=True, verbose_name=b'Contenu', blank=True)), ('content', models.TextField(null=True, verbose_name=b'Contenu', blank=True)),
('commentfield', models.ForeignKey(related_name='values', to='cof.EventCommentField')), ('commentfield', models.ForeignKey(
related_name='values',
on_delete=models.CASCADE,
to='cof.EventCommentField')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -111,7 +120,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=200, verbose_name=b'Option')), ('name', models.CharField(max_length=200, verbose_name=b'Option')),
('multi_choices', models.BooleanField(default=False, verbose_name=b'Choix multiples')), ('multi_choices', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
('event', models.ForeignKey(related_name='options', to='cof.Event')), ('event', models.ForeignKey(
related_name='options',
on_delete=models.CASCADE,
to='cof.Event')),
], ],
options={ options={
'verbose_name': 'Option', 'verbose_name': 'Option',
@ -122,7 +134,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('value', models.CharField(max_length=200, verbose_name=b'Valeur')), ('value', models.CharField(max_length=200, verbose_name=b'Valeur')),
('event_option', models.ForeignKey(related_name='choices', to='cof.EventOption')), ('event_option', models.ForeignKey(
related_name='choices',
on_delete=models.CASCADE,
to='cof.EventOption')),
], ],
options={ options={
'verbose_name': 'Choix', 'verbose_name': 'Choix',
@ -133,10 +148,14 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('paid', models.BooleanField(default=False, verbose_name=b'A pay\xc3\xa9')), ('paid', models.BooleanField(default=False, verbose_name=b'A pay\xc3\xa9')),
('event', models.ForeignKey(to='cof.Event')), ('event', models.ForeignKey(
on_delete=models.CASCADE,
to='cof.Event')),
('filledcomments', models.ManyToManyField(to='cof.EventCommentField', through='cof.EventCommentValue')), ('filledcomments', models.ManyToManyField(to='cof.EventCommentField', through='cof.EventCommentValue')),
('options', models.ManyToManyField(to='cof.EventOptionChoice')), ('options', models.ManyToManyField(to='cof.EventOptionChoice')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Inscription', 'verbose_name': 'Inscription',
@ -240,7 +259,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('question', models.CharField(max_length=200, verbose_name=b'Question')), ('question', models.CharField(max_length=200, verbose_name=b'Question')),
('multi_answers', models.BooleanField(default=False, verbose_name=b'Choix multiples')), ('multi_answers', models.BooleanField(default=False, verbose_name=b'Choix multiples')),
('survey', models.ForeignKey(related_name='questions', to='cof.Survey')), ('survey', models.ForeignKey(
on_delete=models.CASCADE,
related_name='questions',
to='cof.Survey')),
], ],
options={ options={
'verbose_name': 'Question', 'verbose_name': 'Question',
@ -251,7 +273,10 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('answer', models.CharField(max_length=200, verbose_name=b'R\xc3\xa9ponse')), ('answer', models.CharField(max_length=200, verbose_name=b'R\xc3\xa9ponse')),
('survey_question', models.ForeignKey(related_name='answers', to='cof.SurveyQuestion')), ('survey_question', models.ForeignKey(
related_name='answers',
on_delete=models.CASCADE,
to='cof.SurveyQuestion')),
], ],
options={ options={
'verbose_name': 'R\xe9ponse', 'verbose_name': 'R\xe9ponse',
@ -265,12 +290,16 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='surveyanswer', model_name='surveyanswer',
name='survey', name='survey',
field=models.ForeignKey(to='cof.Survey'), field=models.ForeignKey(
on_delete=models.CASCADE,
to='cof.Survey'),
), ),
migrations.AddField( migrations.AddField(
model_name='surveyanswer', model_name='surveyanswer',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursdemande', model_name='petitcoursdemande',
@ -280,47 +309,72 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='petitcoursdemande', model_name='petitcoursdemande',
name='traitee_par', name='traitee_par',
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True), field=models.ForeignKey(
on_delete=models.PROTECT,
blank=True,
to=settings.AUTH_USER_MODEL,
null=True),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattributioncounter', model_name='petitcoursattributioncounter',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Matiere', to='cof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.PROTECT,
verbose_name='Matiere',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattributioncounter', model_name='petitcoursattributioncounter',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.PROTECT,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='demande', name='demande',
field=models.ForeignKey(verbose_name='Demande', to='cof.PetitCoursDemande'), field=models.ForeignKey(
on_delete=models.CASCADE,
verbose_name='Demande',
to='cof.PetitCoursDemande'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Mati\xe8re', to='cof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.PROTECT,
verbose_name='Mati\xe8re',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursattribution', model_name='petitcoursattribution',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursability', model_name='petitcoursability',
name='matiere', name='matiere',
field=models.ForeignKey(verbose_name='Mati\xe8re', to='cof.PetitCoursSubject'), field=models.ForeignKey(
on_delete=models.CASCADE,
verbose_name='Mati\xe8re',
to='cof.PetitCoursSubject'),
), ),
migrations.AddField( migrations.AddField(
model_name='petitcoursability', model_name='petitcoursability',
name='user', name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='eventcommentvalue', model_name='eventcommentvalue',
name='registration', name='registration',
field=models.ForeignKey(related_name='comments', to='cof.EventRegistration'), field=models.ForeignKey(
on_delete=models.CASCADE,
related_name='comments',
to='cof.EventRegistration'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='surveyanswer', name='surveyanswer',

View file

@ -23,7 +23,9 @@ class Migration(migrations.Migration):
('subscribe_to_events', models.BooleanField(default=True)), ('subscribe_to_events', models.BooleanField(default=True)),
('subscribe_to_my_shows', models.BooleanField(default=True)), ('subscribe_to_my_shows', models.BooleanField(default=True)),
('other_shows', models.ManyToManyField(to='bda.Spectacle')), ('other_shows', models.ManyToManyField(to='bda.Spectacle')),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import Group, Permission from django.contrib.auth.models import Group
from django.db import migrations, models from django.db import migrations, models
@ -23,23 +23,23 @@ def create_profile(apps, schema_editor):
def preserve_perms(apps, schema_editor): def preserve_perms(apps, schema_editor):
from django.contrib.auth.management import create_permissions # from django.contrib.auth.management import create_permissions
apps.models_module = True # apps.models_module = True
create_permissions(apps, verbosity=0) # create_permissions(apps, verbosity=0)
apps.models_module = None # apps.models_module = None
CofProfile = apps.get_model("cof", "CofProfile") CofProfile = apps.get_model("cof", "CofProfile")
memberp = Permission.objects.get(codename='member') # memberp = Permission.objects.get(codename='member')
burop = Permission.objects.get(codename='buro') # burop = Permission.objects.get(codename='buro')
# creates the groups for COF members and # creates the groups for COF members and
member = Group.objects.create(name='cof_members') member = Group.objects.create(name='cof_members')
buro = Group.objects.create(name='cof_buro') buro = Group.objects.create(name='cof_buro')
# associate permissions to the respective groups. # associate permissions to the respective groups.
buro.permissions = [burop, memberp] # buro.permissions = [burop, memberp]
member.permissions = [memberp] # member.permissions = [memberp]
for cofp in CofProfile.objects.filter(is_cof=True): for cofp in CofProfile.objects.filter(is_cof=True):
cofp.profile.user.groups.add(member) cofp.profile.user.groups.add(member)
@ -70,6 +70,7 @@ class Migration(migrations.Migration):
model_name='cofprofile', model_name='cofprofile',
name='profile', name='profile',
field=models.OneToOneField( field=models.OneToOneField(
on_delete=models.CASCADE,
to='gestion.Profile', to='gestion.Profile',
null=True, null=True,
related_name='cof' related_name='cof'
@ -89,6 +90,7 @@ class Migration(migrations.Migration):
model_name='cofprofile', model_name='cofprofile',
name='profile', name='profile',
field=models.OneToOneField( field=models.OneToOneField(
on_delete=models.CASCADE,
to='gestion.Profile', to='gestion.Profile',
related_name='cof' related_name='cof'
), ),

View file

@ -0,0 +1,23 @@
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('cof', '0011_delete_clipper_and_custommail'),
('gestion', '0002_club_support')
]
operations = [
migrations.RemoveField(
model_name='club',
name='membres',
),
migrations.RemoveField(
model_name='club',
name='respos',
),
migrations.DeleteModel(
name='Club',
),
]

View file

@ -79,18 +79,6 @@ class CofProfile(models.Model):
return self.profile.user.username return self.profile.user.username
@python_2_unicode_compatible
class Club(models.Model):
name = models.CharField("Nom", max_length=200, unique=True)
description = models.TextField("Description", blank=True)
respos = models.ManyToManyField(User, related_name="clubs_geres",
blank=True)
membres = models.ManyToManyField(User, related_name="clubs", blank=True)
def __str__(self):
return self.name
@python_2_unicode_compatible @python_2_unicode_compatible
class Event(models.Model): class Event(models.Model):
title = models.CharField("Titre", max_length=200) title = models.CharField("Titre", max_length=200)
@ -113,7 +101,11 @@ class Event(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class EventCommentField(models.Model): class EventCommentField(models.Model):
event = models.ForeignKey(Event, related_name="commentfields") event = models.ForeignKey(
Event,
on_delete=models.CASCADE,
related_name="commentfields"
)
name = models.CharField("Champ", max_length=200) name = models.CharField("Champ", max_length=200)
fieldtype = models.CharField("Type", max_length=10, fieldtype = models.CharField("Type", max_length=10,
choices=TYPE_COMMENT_FIELD, default="text") choices=TYPE_COMMENT_FIELD, default="text")
@ -128,9 +120,16 @@ class EventCommentField(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class EventCommentValue(models.Model): class EventCommentValue(models.Model):
commentfield = models.ForeignKey(EventCommentField, related_name="values") commentfield = models.ForeignKey(
registration = models.ForeignKey("EventRegistration", EventCommentField,
related_name="comments") on_delete=models.CASCADE,
related_name="values"
)
registration = models.ForeignKey(
"EventRegistration",
on_delete=models.CASCADE,
related_name="comments"
)
content = models.TextField("Contenu", blank=True, null=True) content = models.TextField("Contenu", blank=True, null=True)
def __str__(self): def __str__(self):
@ -139,7 +138,11 @@ class EventCommentValue(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class EventOption(models.Model): class EventOption(models.Model):
event = models.ForeignKey(Event, related_name="options") event = models.ForeignKey(
Event,
on_delete=models.CASCADE,
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)
@ -152,7 +155,11 @@ class EventOption(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class EventOptionChoice(models.Model): class EventOptionChoice(models.Model):
event_option = models.ForeignKey(EventOption, related_name="choices") event_option = models.ForeignKey(
EventOption,
on_delete=models.CASCADE,
related_name="choices"
)
value = models.CharField("Valeur", max_length=200) value = models.CharField("Valeur", max_length=200)
class Meta: class Meta:
@ -165,8 +172,14 @@ class EventOptionChoice(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class EventRegistration(models.Model): class EventRegistration(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
event = models.ForeignKey(Event) User,
on_delete=models.CASCADE
)
event = models.ForeignKey(
Event,
on_delete=models.CASCADE
)
options = models.ManyToManyField(EventOptionChoice) options = models.ManyToManyField(EventOptionChoice)
filledcomments = models.ManyToManyField(EventCommentField, filledcomments = models.ManyToManyField(EventCommentField,
through=EventCommentValue) through=EventCommentValue)
@ -197,7 +210,11 @@ class Survey(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class SurveyQuestion(models.Model): class SurveyQuestion(models.Model):
survey = models.ForeignKey(Survey, related_name="questions") survey = models.ForeignKey(
Survey,
on_delete=models.CASCADE,
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)
@ -210,7 +227,11 @@ class SurveyQuestion(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class SurveyQuestionAnswer(models.Model): class SurveyQuestionAnswer(models.Model):
survey_question = models.ForeignKey(SurveyQuestion, related_name="answers") survey_question = models.ForeignKey(
SurveyQuestion,
on_delete=models.CASCADE,
related_name="answers"
)
answer = models.CharField("Réponse", max_length=200) answer = models.CharField("Réponse", max_length=200)
class Meta: class Meta:
@ -222,8 +243,14 @@ class SurveyQuestionAnswer(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class SurveyAnswer(models.Model): class SurveyAnswer(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
survey = models.ForeignKey(Survey) User,
on_delete=models.CASCADE
)
survey = models.ForeignKey(
Survey,
on_delete=models.CASCADE
)
answers = models.ManyToManyField(SurveyQuestionAnswer, answers = models.ManyToManyField(SurveyQuestionAnswer,
related_name="selected_by") related_name="selected_by")
@ -240,7 +267,10 @@ class SurveyAnswer(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class CalendarSubscription(models.Model): class CalendarSubscription(models.Model):
token = models.UUIDField() token = models.UUIDField()
user = models.OneToOneField(User) user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
other_shows = models.ManyToManyField(Spectacle) other_shows = models.ManyToManyField(Spectacle)
subscribe_to_events = models.BooleanField(default=True) subscribe_to_events = models.BooleanField(default=True)
subscribe_to_my_shows = models.BooleanField(default=True) subscribe_to_my_shows = models.BooleanField(default=True)

View file

@ -35,8 +35,15 @@ class PetitCoursSubject(models.Model):
class PetitCoursAbility(models.Model): class PetitCoursAbility(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matière")
)
niveau = models.CharField(_("Niveau"), niveau = models.CharField(_("Niveau"),
choices=LEVELS_CHOICES, choices=LEVELS_CHOICES,
max_length=choices_length(LEVELS_CHOICES)) max_length=choices_length(LEVELS_CHOICES))
@ -84,7 +91,11 @@ class PetitCoursDemande(models.Model):
remarques = models.TextField(_("Remarques et précisions"), blank=True) remarques = models.TextField(_("Remarques et précisions"), blank=True)
traitee = models.BooleanField(_("Traitée"), default=False) traitee = models.BooleanField(_("Traitée"), default=False)
traitee_par = models.ForeignKey(User, blank=True, null=True) traitee_par = models.ForeignKey(
User,
on_delete=models.CASCADE,
blank=True, null=True
)
processed = models.DateTimeField(_("Date de traitement"), processed = models.DateTimeField(_("Date de traitement"),
blank=True, null=True) blank=True, null=True)
created = models.DateTimeField(_("Date de création"), auto_now_add=True) created = models.DateTimeField(_("Date de création"), auto_now_add=True)
@ -126,9 +137,20 @@ class PetitCoursDemande(models.Model):
class PetitCoursAttribution(models.Model): class PetitCoursAttribution(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande")) User,
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) on_delete=models.CASCADE
)
demande = models.ForeignKey(
PetitCoursDemande,
on_delete=models.CASCADE,
verbose_name=_("Demande")
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matière")
)
date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True) date = models.DateTimeField(_("Date d'attribution"), auto_now_add=True)
rank = models.IntegerField("Rang dans l'email") rank = models.IntegerField("Rang dans l'email")
selected = models.BooleanField(_("Sélectionné par le demandeur"), selected = models.BooleanField(_("Sélectionné par le demandeur"),
@ -145,8 +167,15 @@ class PetitCoursAttribution(models.Model):
class PetitCoursAttributionCounter(models.Model): class PetitCoursAttributionCounter(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(
matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere")) User,
on_delete=models.CASCADE
)
matiere = models.ForeignKey(
PetitCoursSubject,
on_delete=models.CASCADE,
verbose_name=_("Matiere")
)
count = models.IntegerField("Nombre d'envois", default=0) count = models.IntegerField("Nombre d'envois", default=0)
@classmethod @classmethod

View file

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<header> <header>
<div class="container banner"> <div class="container banner">
<a href="{% url "cof.views.home" %}"> <a href="{% url "home" %}">
<h1>GestioCOF</h1> <h1>GestioCOF</h1>
{% block homelink %} {% block homelink %}
<span class="glyphicon glyphicon-home" aria-hidden=true></span> <span class="glyphicon glyphicon-home" aria-hidden=true></span>

View file

@ -12,7 +12,7 @@ souscrire aux événements du COF et/ou aux spectacles BdA.
{% if token %} {% if token %}
<p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à <p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à
<a href="{% url 'cof.views.calendar_ics' token %}">cette adresse</a>.</p> <a href="{% url 'calendar.ics' token %}">cette adresse</a>.</p>
<ul> <ul>
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller <li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller

View file

@ -8,7 +8,7 @@
{% if event.details %} {% if event.details %}
<p>{{ event.details }}</p> <p>{{ event.details }}</p>
{% endif %} {% endif %}
<form method="post" action="{% url 'cof.views.event' event.id %}"> <form method="post" action="{% url 'event' event.id %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" class="btn-submit" value="Enregistrer" /> <input type="submit" class="btn-submit" value="Enregistrer" />

View file

@ -7,7 +7,7 @@
{% else %} {% else %}
<h3>Inscription d'un nouveau compte (extérieur ?)</h3> <h3>Inscription d'un nouveau compte (extérieur ?)</h3>
{% endif %} {% endif %}
<form role="form" id="profile" method="post" action="{% url 'cof.views.registration' %}"> <form role="form" id="profile" method="post" action="{% url 'registration' %}">
{% csrf_token %} {% csrf_token %}
<table> <table>
{{ user_form | bootstrap }} {{ user_form | bootstrap }}
@ -16,7 +16,6 @@
<hr /> <hr />
<table> <table>
{{ cofprofile_form | bootstrap }} {{ cofprofile_form | bootstrap }}
{{ clubs_form | bootstrap }}
</table> </table>
{{ event_formset.management_form }} {{ event_formset.management_form }}
{% for event_form in event_formset %} {% for event_form in event_formset %}

View file

@ -15,7 +15,7 @@
{% if survey.details %} {% if survey.details %}
<p>{{ survey.details }}</p> <p>{{ survey.details }}</p>
{% endif %} {% endif %}
<form class="form-horizontal" method="post" action="{% url 'cof.views.survey' survey.id %}"> <form class="form-horizontal" method="post" action="{% url 'survey' survey.id %}">
{% csrf_token %} {% csrf_token %}
{{ form | bootstrap}} {{ form | bootstrap}}

View file

@ -7,15 +7,15 @@
<h2>Liens utiles du COF</h2> <h2>Liens utiles du COF</h2>
<h3>COF</h3> <h3>COF</h3>
<ul> <ul>
<li><a href="{% url 'cof.views.export_members' %}">Export des membres du COF</a></li> <li><a href="{% url 'export.members' %}">Export des membres du COF</a></li>
<li><a href="{% url 'cof.views.liste_diffcof' %}">Diffusion COF</a></li> <li><a href="{% url 'liste_diffcof' %}">Diffusion COF</a></li>
</ul> </ul>
<h3>Mega</h3> <h3>Mega</h3>
<ul> <ul>
<li><a href="{% url 'cof.views.export_mega_participants' %}">Export des non-orgas uniquement</a></li> <li><a href="{% url 'export.mega.participants' %}">Export des non-orgas uniquement</a></li>
<li><a href="{% url 'cof.views.export_mega_orgas' %}">Export des orgas uniquement</a></li> <li><a href="{% url 'export.mega.orgas' %}">Export des orgas uniquement</a></li>
<li><a href="{% url 'cof.views.export_mega' %}">Export de tout le monde</a></li> <li><a href="{% url 'export.mega' %}">Export de tout le monde</a></li>
</ul> </ul>
<p>Note&nbsp;: pour ouvrir les fichiers .csv avec Excel, il faut <p>Note&nbsp;: pour ouvrir les fichiers .csv avec Excel, il faut

View file

@ -11,7 +11,7 @@
{% endif %} {% endif %}
{% include "tristate_js.html" %} {% include "tristate_js.html" %}
<h3>Filtres</h3> <h3>Filtres</h3>
<form method="post" action="{% url 'cof.views.event_status' event.id %}"> <form method="post" action="{% url 'event.status' event.id %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input style="margin-top:10px;" type="submit" class="btn btn-primary" value="Filtrer" /> <input style="margin-top:10px;" type="submit" class="btn btn-primary" value="Filtrer" />

View file

@ -13,7 +13,7 @@
<div class="hm-block"> <div class="hm-block">
<ul> <ul>
{% for event in open_events %} {% for event in open_events %}
<li><a href="{% url "cof.views.event" event.id %}">{{ event.title }}</a></li> <li><a href="{% url "event" event.id %}">{{ event.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -23,7 +23,7 @@
<div class="hm-block"> <div class="hm-block">
<ul> <ul>
{% for survey in open_surveys %} {% for survey in open_surveys %}
<li><a href="{% url "cof.views.survey" survey.id %}">{{ survey.title }}</a></li> <li><a href="{% url "survey" survey.id %}">{{ survey.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -54,11 +54,11 @@
<h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3> <h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3>
<div class="hm-block"> <div class="hm-block">
<ul> <ul>
<li><a href="{% url "cof.views.calendar" %}">Calendrier dynamique</a></li> <li><a href="{% url "calendar" %}">Calendrier dynamique</a></li>
{% if user.profile.cof.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %} {% if user.profile.cof.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %}
<li><a href="{% url "gestion:profile" %}">Éditer mon profil</a></li> <li><a href="{% url "gestion:profile" %}">Éditer mon profil</a></li>
{% if not user.profile.login_clipper %}<li><a href="{% url "django.contrib.auth.views.password_change" %}">Changer mon mot de passe</a></li>{% endif %} {% if not user.profile.login_clipper %}<li><a href="{% url "password_change" %}">Changer mon mot de passe</a></li>{% endif %}
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
@ -71,16 +71,15 @@
<h4>Général</h4> <h4>Général</h4>
<li><a href="{% url "admin:index" %}">Administration générale</a></li> <li><a href="{% url "admin:index" %}">Administration générale</a></li>
<li><a href="{% url "petits-cours-demandes-list" %}">Demandes de petits cours</a></li> <li><a href="{% url "petits-cours-demandes-list" %}">Demandes de petits cours</a></li>
<li><a href="{% url "cof.views.registration" %}">Inscription d'un nouveau membre</a></li> <li><a href="{% url "registration" %}">Inscription d'un nouveau membre</a></li>
<li><a href="{% url "liste-clubs" %}">Gestion des clubs</a></li>
</ul> </ul>
<ul> <ul>
<h4>Évènements & Sondages</h4> <h4>Évènements & Sondages</h4>
{% for event in events %} {% for event in events %}
<li><a href="{% url "cof.views.event_status" event.id %}">Événement : {{ event.title }}</a></li> <li><a href="{% url "event.status" event.id %}">Événement : {{ event.title }}</a></li>
{% endfor %} {% endfor %}
{% for survey in surveys %} {% for survey in surveys %}
<li><a href="{% url "cof.views.survey_status" survey.id %}">Sondage : {{ survey.title }}</a></li> <li><a href="{% url "survey.status" survey.id %}">Sondage : {{ survey.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -105,8 +104,8 @@
<h3 class="block-title">Liens utiles<span class="pull-right glyphicon glyphicon-link"></span></h3> <h3 class="block-title">Liens utiles<span class="pull-right glyphicon glyphicon-link"></span></h3>
<div class="hm-block"> <div class="hm-block">
<ul> <ul>
<li><a href="{% url "cof.views.utile_cof" %}">Liens utiles du COF</a></li> <li><a href="{% url "utile_cof" %}">Liens utiles du COF</a></li>
<li><a href="{% url "cof.views.utile_bda" %}">Liens utiles BdA</a></li> <li><a href="{% url "utile_bda" %}">Liens utiles BdA</a></li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -1,25 +0,0 @@
{% extends "base_title.html" %}
{% block page_size %}col-sm-8{% endblock %}
{% block realcontent %}
<h2>Clubs enregistrés sur GestioCOF</h2>
<ul>
{% for club in owned_clubs %}
<li>
<a href="{% url "membres-club" club.name %}">
{{ club }} ({% for respo in club.respos.all %}{{ respo.get_full_name }}, {% empty %}pas de respo{% endfor %})
</a>
</li>
{% endfor %}
{% if other_clubs %}
{% for club in other_clubs %}
<li>
<p>
{{ club }} ({% for respo in club.respos.all %}{{ respo.get_full_name }}, {% empty %}pas de respo{% endfor %})
</p>
</li>
{% endfor %}
{% endif %}
</ul>
{% endblock %}

View file

@ -1,41 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>{{ club }}</h2>
{% if club.respos.exists %}
<h3>Respo{{ club.respos.all|pluralize }}</h3>
<table class="table table-striped">
{% for member in club.respos.all %}
<tr>
<td>{{ member }}</td>
<td>{{ member.email }}</td>
<td><a class="glyphicon glyphicon-arrow-down"
href="{% url "change-respo" club.name member.id %}"></a></td>
</tr>
{% endfor %}
</table>
{% else %}
<h3>Pas de respo</h3>
{% endif %}
{% if club.membres.exists %}
<h3>Liste des membres</h3>
<table class="table table-striped">
{% for member in members_no_respo %}
<tr>
<td>{{ member }}</td>
<td>{{ member.email }}</td>
<td><a class="glyphicon glyphicon-arrow-up"
href="{% url "change-respo" club.name member.id %}"></a></td>
</tr>
{% endfor %}
</table>
{% else %}
Ce club ne comporte actuellement aucun membre.
{% endif %}
{% endblock %}

View file

@ -16,7 +16,7 @@
// On attend que la page soit prête pour executer le code // On attend que la page soit prête pour executer le code
$(document).ready(function() { $(document).ready(function() {
$('input#search_autocomplete').yourlabsAutocomplete({ $('input#search_autocomplete').yourlabsAutocomplete({
url: '{% url 'cof.autocomplete.autocomplete' %}', url: '{% url 'autocomplete' %}',
minimumCharacters: 3, minimumCharacters: 3,
id: 'search_autocomplete', id: 'search_autocomplete',
choiceSelector: 'li:has(a)', choiceSelector: 'li:has(a)',

View file

@ -5,5 +5,5 @@
{% block realcontent %} {% block realcontent %}
<h2>Mot de passe modifié avec succès !</h2> <h2>Mot de passe modifié avec succès !</h2>
<h3><a href="{% url "cof.views.home" %}">Retour au menu principal</a></h3> <h3><a href="{% url "home" %}">Retour au menu principal</a></h3>
{% endblock %} {% endblock %}

View file

@ -5,7 +5,7 @@
{% block realcontent %} {% block realcontent %}
<h2>Changement de mot de passe</h2> <h2>Changement de mot de passe</h2>
<form class="form-horizontal" method="post" action="{% url 'django.contrib.auth.views.password_change' %}"> <form class="form-horizontal" method="post" action="{% url 'password_change' %}">
{% csrf_token %} {% csrf_token %}
{{ form | bootstrap }} {{ form | bootstrap }}
<input type="submit" class="btn btn-primary pull-right" value="Changer" /> <input type="submit" class="btn btn-primary pull-right" value="Changer" />

View file

@ -11,7 +11,7 @@
{% endif %} {% endif %}
<h3>Filtres</h3> <h3>Filtres</h3>
{% include "tristate_js.html" %} {% include "tristate_js.html" %}
<form method="post" action="{% url 'cof.views.survey_status' survey.id %}"> <form method="post" action="{% url 'survey.status' survey.id %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<input style="margin-top:10px;" type="submit" class="btn btn-primary" value="Filtrer" /> <input style="margin-top:10px;" type="submit" class="btn btn-primary" value="Filtrer" />

View file

@ -7,7 +7,7 @@
<h2>Liens utiles du BdA</h2> <h2>Liens utiles du BdA</h2>
<h3>Listes mail</h3> <h3>Listes mail</h3>
<ul> <ul>
<li><a href="{% url 'cof.views.liste_bdadiff' %}">BdA diffusion</a></li> <li><a href="{% url 'liste_bdadiff' %}">BdA diffusion</a></li>
<li><a href="{% url 'cof.views.liste_bdarevente' %}">BdA revente</a></li> <li><a href="{% url 'liste_bdarevente' %}">BdA revente</a></li>
</ul> </ul>
{% endblock %} {% endblock %}

View file

@ -7,12 +7,20 @@ from . import views, petits_cours_views
export_patterns = [ export_patterns = [
url(r'^members$', views.export_members), url(r'^members$',
views.export_members,
name="export.members"),
url(r'^mega/avecremarques$', views.export_mega_remarksonly), url(r'^mega/avecremarques$', views.export_mega_remarksonly),
url(r'^mega/participants$', views.export_mega_participants), url(r'^mega/participants$',
url(r'^mega/orgas$', views.export_mega_orgas), views.export_mega_participants,
name="export.mega.participants"),
url(r'^mega/orgas$',
views.export_mega_orgas,
name="export.mega.orgas"),
url(r'^mega/(?P<type>.+)$', views.export_mega_bytype), url(r'^mega/(?P<type>.+)$', views.export_mega_bytype),
url(r'^mega$', views.export_mega), url(r'^mega$',
views.export_mega,
name="export.mega"),
] ]
petitcours_patterns = [ petitcours_patterns = [
@ -37,24 +45,28 @@ petitcours_patterns = [
] ]
surveys_patterns = [ surveys_patterns = [
url(r'^(?P<survey_id>\d+)/status$', views.survey_status), url(r'^(?P<survey_id>\d+)/status$',
url(r'^(?P<survey_id>\d+)$', views.survey), views.survey_status,
name="survey.status"),
url(r'^(?P<survey_id>\d+)$',
views.survey,
name="survey"),
] ]
events_patterns = [ events_patterns = [
url(r'^(?P<event_id>\d+)$', views.event), url(r'^(?P<event_id>\d+)$',
url(r'^(?P<event_id>\d+)/status$', views.event_status), views.event,
name="event"),
url(r'^(?P<event_id>\d+)/status$',
views.event_status,
name="event.status"),
] ]
calendar_patterns = [ calendar_patterns = [
url(r'^subscription$', 'cof.views.calendar'), url(r'^subscription$',
views.calendar,
name="calendar"),
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$', url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$',
'cof.views.calendar_ics') views.calendar_ics,
] name="calendar.ics")
clubs_patterns = [
url(r'^membres/(?P<name>\w+)', views.membres_club, name='membres-club'),
url(r'^liste', views.liste_clubs, name='liste-clubs'),
url(r'^change_respo/(?P<club_name>\w+)/(?P<user_id>\d+)',
views.change_respo, name='change-respo'),
] ]

View file

@ -6,8 +6,8 @@ from datetime import timedelta
from icalendar import Calendar, Event as Vevent from icalendar import Calendar, Event as Vevent
from custommail.shortcuts import send_custom_mail from custommail.shortcuts import send_custom_mail
from django.shortcuts import redirect, get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.http import Http404, HttpResponse, HttpResponseForbidden from django.http import Http404, HttpResponse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
@ -21,12 +21,12 @@ from .models import Event, EventRegistration, EventOption, \
EventOptionChoice EventOptionChoice
from .models import EventCommentField, EventCommentValue, \ from .models import EventCommentField, EventCommentValue, \
CalendarSubscription CalendarSubscription
from .models import CofProfile, Club from .models import CofProfile
from .decorators import buro_required, cof_required from .decorators import buro_required, cof_required
from .forms import ( from .forms import (
EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm, EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
RegistrationUserForm, RegistrationProfileForm, RegistrationCofProfileForm, RegistrationUserForm, RegistrationProfileForm, RegistrationCofProfileForm,
EventForm, CalendarForm, EventFormset, RegistrationPassUserForm, ClubsForm EventForm, CalendarForm, EventFormset, RegistrationPassUserForm
) )
from bda.models import Tirage, Spectacle from bda.models import Tirage, Spectacle
@ -305,9 +305,8 @@ def registration_form2(request, login_clipper=None, username=None,
# COF - profile # COF - profile
cofprofile_form = RegistrationCofProfileForm() cofprofile_form = RegistrationCofProfileForm()
registration_set_ro_fields(user_form, profile_form) registration_set_ro_fields(user_form, profile_form)
# events & clubs # events
event_formset = EventFormset(events=events, prefix='events') event_formset = EventFormset(events=events, prefix='events')
clubs_form = ClubsForm()
if username: if username:
member = get_object_or_404(User, username=username) member = get_object_or_404(User, username=username)
(profile, _) = Profile.objects.get_or_create(user=member) (profile, _) = Profile.objects.get_or_create(user=member)
@ -328,8 +327,6 @@ def registration_form2(request, login_clipper=None, username=None,
event_formset = EventFormset( event_formset = EventFormset(
events=events, prefix='events', events=events, prefix='events',
current_registrations=current_registrations) current_registrations=current_registrations)
# Clubs
clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
elif not login_clipper: elif not login_clipper:
# new user # new user
user_form = RegistrationPassUserForm() user_form = RegistrationPassUserForm()
@ -337,14 +334,12 @@ def registration_form2(request, login_clipper=None, username=None,
profile_form = RegistrationProfileForm() profile_form = RegistrationProfileForm()
cofprofile_form = RegistrationCofProfileForm() cofprofile_form = RegistrationCofProfileForm()
event_formset = EventFormset(events=events, prefix='events') event_formset = EventFormset(events=events, prefix='events')
clubs_form = ClubsForm()
return render(request, "cof/registration_form.html", return render(request, "cof/registration_form.html",
{"member": member, "login_clipper": login_clipper, {"member": member, "login_clipper": login_clipper,
"user_form": user_form, "user_form": user_form,
"profile_form": profile_form, "profile_form": profile_form,
"cofprofile_form": cofprofile_form, "cofprofile_form": cofprofile_form,
"event_formset": event_formset, "event_formset": event_formset})
"clubs_form": clubs_form})
@buro_required @buro_required
@ -368,7 +363,6 @@ def registration(request):
user_form = RegistrationUserForm(request_dict) user_form = RegistrationUserForm(request_dict)
profile_form = RegistrationProfileForm(request_dict) profile_form = RegistrationProfileForm(request_dict)
cofprofile_form = RegistrationCofProfileForm(request_dict) cofprofile_form = RegistrationCofProfileForm(request_dict)
clubs_form = ClubsForm(request_dict)
events = Event.objects.filter(old=False).all() events = Event.objects.filter(old=False).all()
event_formset = EventFormset(events=events, data=request_dict, event_formset = EventFormset(events=events, data=request_dict,
prefix='events') prefix='events')
@ -409,7 +403,6 @@ def registration(request):
profile_form.is_valid(), profile_form.is_valid(),
cofprofile_form.is_valid(), cofprofile_form.is_valid(),
event_formset.is_valid(), event_formset.is_valid(),
clubs_form.is_valid()
)) ))
if forms_are_valid: if forms_are_valid:
# Enregistrement du profil # Enregistrement du profil
@ -455,11 +448,6 @@ def registration(request):
# l'inscription aux événements et/ou donner la # l'inscription aux événements et/ou donner la
# possibilité d'associer un mail aux événements # possibilité d'associer un mail aux événements
# send_custom_mail(...) # send_custom_mail(...)
# Enregistrement des inscriptions aux clubs
member.clubs.clear()
for club in clubs_form.cleaned_data['clubs']:
club.membres.add(member)
club.save()
success = True success = True
# Messages # Messages
if success: if success:
@ -476,56 +464,11 @@ def registration(request):
"cofprofile_form": cofprofile_form, "cofprofile_form": cofprofile_form,
"member": member, "member": member,
"login_clipper": login_clipper, "login_clipper": login_clipper,
"event_formset": event_formset, "event_formset": event_formset})
"clubs_form": clubs_form})
else: else:
return render(request, "registration.html") return render(request, "registration.html")
# -----
# Clubs
# -----
@login_required
def membres_club(request, name):
# Vérification des permissions : l'utilisateur doit être membre du burô
# ou respo du club.
user = request.user
club = get_object_or_404(Club, name=name)
if not request.user.profile.is_buro \
and club not in user.clubs_geres.all():
return HttpResponseForbidden('<h1>Permission denied</h1>')
members_no_respo = club.membres.exclude(clubs_geres=club).all()
return render(request, 'membres_clubs.html',
{'club': club,
'members_no_respo': members_no_respo})
@buro_required
def change_respo(request, club_name, user_id):
club = get_object_or_404(Club, name=club_name)
user = get_object_or_404(User, id=user_id)
if user in club.respos.all():
club.respos.remove(user)
elif user in club.membres.all():
club.respos.add(user)
else:
raise Http404
return redirect('membres-club', name=club_name)
@cof_required
def liste_clubs(request):
clubs = Club.objects
if request.user.profile.is_buro:
data = {'owned_clubs': clubs.all()}
else:
data = {'owned_clubs': request.user.clubs_geres,
'other_clubs': clubs.exclude(respos=request.user)}
return render(request, 'liste_clubs.html', data)
@buro_required @buro_required
def export_members(request): def export_members(request):
response = HttpResponse(content_type='text/csv') response = HttpResponse(content_type='text/csv')

View file

@ -42,26 +42,26 @@ INSTALLED_APPS = (
'bootstrapform', 'bootstrapform',
'channels', 'channels',
'widget_tweaks', 'widget_tweaks',
'bda',
'bds',
'cof',
'gestion',
'kfet',
'custommail', 'custommail',
'bda.apps.BdAConfig',
'bds.apps.BDSConfig',
'cof.apps.COFConfig',
'gestion.apps.GestionConfig',
'kfet.apps.KFetConfig',
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'kfet.middleware.KFetAuthenticationMiddleware', 'kfet.middleware.kfet_auth_middleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
) ]
ROOT_URLCONF = 'gestioCOF.urls' ROOT_URLCONF = 'gestioCOF.urls'
@ -76,9 +76,6 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'gestion.context_processors.context_processor', 'gestion.context_processors.context_processor',
'kfet.context_processors.auth', 'kfet.context_processors.auth',
], ],

View file

@ -4,7 +4,9 @@
Fichier principal de configuration des urls du projet GestioCOF Fichier principal de configuration des urls du projet GestioCOF
""" """
import autocomplete_light import gestion.urls
import kfet.urls
import bda.urls
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
@ -14,26 +16,24 @@ from django.contrib.auth import views as django_views
from cof import views as cof_views from cof import views as cof_views
from cof.urls import export_patterns, petitcours_patterns, \ from cof.urls import export_patterns, petitcours_patterns, \
surveys_patterns, events_patterns, calendar_patterns, \ surveys_patterns, events_patterns, calendar_patterns
clubs_patterns
from cof.autocomplete import autocomplete from cof.autocomplete import autocomplete
from gestion import views as gestion_views from gestion import views as gestion_views
autocomplete_light.autodiscover()
admin.autodiscover() admin.autodiscover()
urlpatterns = [ urlpatterns = [
# Page d'accueil # Page d'accueil
url(r'^$', cof_views.home, name='home'), url(r'^$', cof_views.home, name='home'),
# The common views # The common views
url(r"^", include("gestion.urls", namespace='gestion')), url(r"^", include(gestion.urls, namespace="gestion")),
# Admin urls # Admin urls
url(r'^admin/logout/', gestion_views.logout), url(r'^admin/logout/', gestion_views.logout),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', admin.site.urls),
# 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
@ -44,15 +44,17 @@ urlpatterns = [
url(r'^event/', include(events_patterns)), url(r'^event/', include(events_patterns)),
# Calendrier # Calendrier
url(r'^calendar/', include(calendar_patterns)), url(r'^calendar/', include(calendar_patterns)),
# Clubs
url(r'^clubs/', include(clubs_patterns)),
# Infos persos # Infos persos
url(r'^outsider/password-change$', django_views.password_change), url(r'^outsider/password-change$',
django_views.password_change,
name="password_change"),
url(r'^outsider/password-change-done$', url(r'^outsider/password-change-done$',
django_views.password_change_done, django_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$', cof_views.registration), url(r'^registration$',
cof_views.registration,
name="registration"),
url(r'^registration/clipper/(?P<login_clipper>[\w-]+)$', url(r'^registration/clipper/(?P<login_clipper>[\w-]+)$',
cof_views.registration_form2, name="clipper-registration"), cof_views.registration_form2, name="clipper-registration"),
url(r'^registration/user/(?P<username>.+)$', url(r'^registration/user/(?P<username>.+)$',
@ -60,21 +62,33 @@ urlpatterns = [
url(r'^registration/empty$', cof_views.registration_form2, url(r'^registration/empty$', cof_views.registration_form2,
name="empty-registration"), name="empty-registration"),
# Autocompletion # Autocompletion
url(r'^autocomplete/registration$', autocomplete), url(r'^autocomplete/registration$',
autocomplete,
name="autocomplete"),
url(r'^autocomplete/', include('autocomplete_light.urls')), url(r'^autocomplete/', include('autocomplete_light.urls')),
# Liens utiles du COF et du BdA # Liens utiles du COF et du BdA
url(r'^utile_cof$', cof_views.utile_cof), url(r'^utile_cof$',
url(r'^utile_bda$', cof_views.utile_bda), cof_views.utile_cof,
url(r'^utile_bda/bda_diff$', cof_views.liste_bdadiff), name="utile_cof"),
url(r'^utile_cof/diff_cof$', cof_views.liste_diffcof), url(r'^utile_bda$',
url(r'^utile_bda/bda_revente$', cof_views.liste_bdarevente), cof_views.utile_bda,
url(r'^k-fet/', include('kfet.urls')), name="utile_bda"),
url(r'^utile_bda/bda_diff$',
cof_views.liste_bdadiff,
name="liste_bdadiff"),
url(r'^utile_cof/diff_cof$',
cof_views.liste_diffcof,
name="liste_diffcof"),
url(r'^utile_bda/bda_revente$',
cof_views.liste_bdarevente,
name="liste_bdarevente"),
url(r'^k-fet/', include(kfet.urls)),
] ]
if 'debug_toolbar' in settings.INSTALLED_APPS: if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar import debug_toolbar
urlpatterns += [ urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^__debug__/', debug_toolbar.urls),
] ]
# Si on est en production, MEDIA_ROOT est servi par Apache. # Si on est en production, MEDIA_ROOT est servi par Apache.

View file

@ -2,9 +2,13 @@ from django.contrib import admin
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import Profile from .models import Profile, Club
# ---
# The user related stuff
# ---
class ProfileInline(admin.StackedInline): class ProfileInline(admin.StackedInline):
model = Profile model = Profile
inline_classes = ["collapse open"] inline_classes = ["collapse open"]
@ -16,5 +20,14 @@ class UserProfileAdmin(UserAdmin):
] ]
# ---
# Clubs
# ---
@admin.register(Club)
class ClubAdmin(admin.ModelAdmin):
pass
admin.site.unregister(User) admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin) admin.site.register(User, UserProfileAdmin)

6
gestion/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class GestionConfig(AppConfig):
name = "gestion"
verbose_name = "Gestion des outils communs COF/BDS"

View file

@ -21,7 +21,10 @@ class Migration(migrations.Migration):
('occupation', models.CharField(choices=[('exterieur', 'Extérieur'), ('1A', '1A'), ('2A', '2A'), ('3A', '3A'), ('4A', '4A'), ('archicube', 'Archicube'), ('doctorant', 'Doctorant'), ('CST', 'CST')], verbose_name='Occupation', max_length=9, default='1A')), ('occupation', models.CharField(choices=[('exterieur', 'Extérieur'), ('1A', '1A'), ('2A', '2A'), ('3A', '3A'), ('4A', '4A'), ('archicube', 'Archicube'), ('doctorant', 'Doctorant'), ('CST', 'CST')], verbose_name='Occupation', max_length=9, default='1A')),
('departement', models.CharField(verbose_name='Département', max_length=50, blank=True)), ('departement', models.CharField(verbose_name='Département', max_length=50, blank=True)),
('comments', models.TextField(verbose_name="Commentaires visibles par l'utilisateur", blank=True)), ('comments', models.TextField(verbose_name="Commentaires visibles par l'utilisateur", blank=True)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='profile')), ('user', models.OneToOneField(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL,
related_name='profile')),
], ],
options={ options={
'verbose_name': 'Profil', 'verbose_name': 'Profil',

View file

@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
def keep_cof_clubs(apps, schema_editor):
Group = apps.get_model("auth", "Group")
CofClub = apps.get_model("cof", "Club")
NewClub = apps.get_model("gestion", "Club")
Registration = apps.get_model("gestion", "ClubUser")
cof_group = Group.objects.get(name="cof_members")
for oldclub in CofClub.objects.all():
newclub = NewClub.objects.create(
name=oldclub.name,
description=oldclub.description,
)
for user in oldclub.membres.all():
Registration.objects.create(
club=newclub,
user=user,
has_paid=True
)
for user in oldclub.respos.all():
reg = Registration.objects.get_or_create(
user=user,
club=newclub
)
reg.is_respo = True
reg.save()
newclub.associations.add(cof_group)
newclub.save()
def restore_cof_clubs(apps, schema_editor):
Group = apps.get_model("auth", "Group")
Club = apps.get_model("cof", "Club")
Registration = apps.get_model("gestion", "ClubUser")
cof_group = Group.objects.get(name="cof_members")
for newclub in cof_group.clubs.all():
club = Club.objects.create(
name=newclub.name,
description=newclub.description
)
for reg in Registration.objects.filter(club=newclub):
if reg.is_respo:
club.respos.add(reg.user)
else:
club.membres.add(reg.user)
class Migration(migrations.Migration):
dependencies = [
('auth', '0006_require_contenttypes_0002'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cof', '0011_delete_clipper_and_custommail'),
('gestion', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Club',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('name', models.CharField(unique=True, max_length=200, verbose_name='Nom')),
('description', models.TextField(verbose_name='Description', blank=True)),
('price', models.DecimalField(verbose_name='Cotisation (€)', decimal_places=2, default=0, blank=True, max_digits=5)),
('cotisation_frequency', models.CharField(choices=[('ANN', 'Annuel'), ('SEM', 'Semestriel'), ('COU', 'Au cours')], max_length=3, verbose_name='Fréquence de la cotisation', default='ANN', blank=True)),
('associations', models.ManyToManyField(to='auth.Group', related_name='clubs')),
],
),
migrations.CreateModel(
name='ClubUser',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('is_respo', models.BooleanField(verbose_name='Est responsable du club')),
('has_paid', models.BooleanField(verbose_name='A payé sa cotisation')),
('club', models.ForeignKey(
to='gestion.Club',
on_delete=models.CASCADE)),
('user', models.ForeignKey(
on_delete=models.CASCADE,
to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='club',
name='members',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, related_name='in_clubs', through='gestion.ClubUser', blank=True),
),
migrations.RunPython(keep_cof_clubs, restore_cof_clubs),
]

View file

@ -1,4 +1,4 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User, Group
from django.db import models from django.db import models
from django.dispatch import receiver from django.dispatch import receiver
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
@ -17,9 +17,13 @@ OCCUPATION_CHOICES = (
('CST', _("CST")), ('CST', _("CST")),
) )
class Profile(models.Model):
user = models.OneToOneField(User, related_name="profile")
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
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)
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(_("Occupation"), occupation = models.CharField(_("Occupation"),
@ -39,6 +43,7 @@ class Profile(models.Model):
def __str__(self): def __str__(self):
return self.user.username return self.user.username
@receiver(post_save, sender=User) @receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs): def create_user_profile(sender, instance, created, **kwargs):
if created: if created:
@ -48,3 +53,53 @@ def create_user_profile(sender, instance, created, **kwargs):
@receiver(post_delete, sender=Profile) @receiver(post_delete, sender=Profile)
def post_delete_user(sender, instance, *args, **kwargs): def post_delete_user(sender, instance, *args, **kwargs):
instance.user.delete() instance.user.delete()
class Club(models.Model):
ANNUAL = "ANN"
SEMESTER = "SEM"
COURSE = "COU"
COTISATION_FREQUENCY_CHOICES = [
(ANNUAL, _("Annuel")),
(SEMESTER, _("Semestriel")),
(COURSE, _("Au cours"))
]
associations = models.ManyToManyField(Group, related_name="clubs")
name = models.CharField(_("Nom"), max_length=200, unique=True)
description = models.TextField("Description", blank=True)
members = models.ManyToManyField(
User,
through="ClubUser",
related_name="in_clubs",
blank=True
)
price = models.DecimalField(
_("Cotisation (€)"),
decimal_places=2,
max_digits=5,
blank=True,
default=0
)
cotisation_frequency = models.CharField(
_("Fréquence de la cotisation"),
default=ANNUAL,
choices=COTISATION_FREQUENCY_CHOICES,
max_length=3,
blank=True
)
def __str__(self):
template = (
self.price and "{name} ({price}€ / {cotisation_frequency})"
or "{name}"
)
return template.format(**vars(self))
class ClubUser(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
club = models.ForeignKey(Club, on_delete=models.CASCADE)
is_respo = models.BooleanField(_("Est responsable du club"))
has_paid = models.BooleanField(_("A payé sa cotisation"))

View file

@ -1,12 +1,11 @@
from django.conf.urls import url, include from django.conf.urls import url
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.contrib.auth import views as django_views from django.contrib.auth import views as django_views
from django.contrib import admin
from django_cas_ng import views as django_cas_views from django_cas_ng import views as django_cas_views
from . import views from . import views
app_name = "gestion"
urlpatterns = [ urlpatterns = [
# Profile edition # Profile edition
url(r"^profile/?$", views.profile, name="profile"), url(r"^profile/?$", views.profile, name="profile"),

View file

@ -16,7 +16,7 @@ from .forms import ProfileForm, UserForm
def login(request): def login(request):
if request.user.is_authenticated(): if request.user.is_authenticated():
return redirect("cof.views.home") return redirect("home")
context = {} context = {}
# Fetch the next page from the request data # Fetch the next page from the request data
if request.method == "GET" and 'next' in request.GET: if request.method == "GET" and 'next' in request.GET:

View file

@ -1,11 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import *
from django.apps import AppConfig from django.apps import AppConfig
class KFetConfig(AppConfig): class KFetConfig(AppConfig):
name = 'kfet' name = 'kfet'
verbose_name = "Application K-Fêt" verbose_name = "Application K-Fêt"

View file

@ -1,15 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import *
import hashlib import hashlib
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
from cof.models import CofProfile
from kfet.models import Account, GenericTeamToken from kfet.models import Account, GenericTeamToken
class KFetBackend(object): class KFetBackend(object):
def authenticate(self, request): def authenticate(self, request):
password = request.POST.get('KFETPASSWORD', '') password = request.POST.get('KFETPASSWORD', '')
@ -17,8 +13,8 @@ class KFetBackend(object):
if not password: if not password:
return None return None
password_sha256 = hashlib.sha256(password.encode('utf-8')).hexdigest()
try: try:
password_sha256 = hashlib.sha256(password.encode('utf-8')).hexdigest()
account = Account.objects.get(password=password_sha256) account = Account.objects.get(password=password_sha256)
user = account.profile.user user = account.profile.user
except Account.DoesNotExist: except Account.DoesNotExist:
@ -26,16 +22,20 @@ class KFetBackend(object):
return user return user
class GenericTeamBackend(object): class GenericTeamBackend(object):
"""
Authenticate using the generic_team user.
"""
def authenticate(self, username=None, token=None): def authenticate(self, username=None, token=None):
valid_token = GenericTeamToken.objects.get(token=token) valid_token = GenericTeamToken.objects.get(token=token)
if username == 'kfet_genericteam' and valid_token: if username == 'kfet_genericteam' and valid_token:
# Création du user s'il n'existe pas déjà # Création du user s'il n'existe pas déjà
user, _ = User.objects.get_or_create(username='kfet_genericteam') user, _ = User.objects.get_or_create(username='kfet_genericteam')
profile, _ = CofProfile.objects.get_or_create(user=user)
account, _ = Account.objects.get_or_create( account, _ = Account.objects.get_or_create(
profile=profile, profile=user.profile,
trigramme='GNR') trigramme='GNR'
)
# Ajoute la permission kfet.is_team à ce user # Ajoute la permission kfet.is_team à ce user
perm_is_team = Permission.objects.get(codename='is_team') perm_is_team = Permission.objects.get(codename='is_team')

View file

@ -1,17 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import *
from django.http import HttpResponseForbidden
from kfet.backends import KFetBackend from kfet.backends import KFetBackend
from kfet.models import Account
class KFetAuthenticationMiddleware(object):
def process_request(self, request): def kfet_auth_middleware(get_response):
kfet_backend = KFetBackend() kfet_backend = KFetBackend()
def middleware(request):
temp_request_user = kfet_backend.authenticate(request) temp_request_user = kfet_backend.authenticate(request)
if temp_request_user: if temp_request_user:
request.real_user = request.user request.real_user = request.user
request.user = temp_request_user request.user = temp_request_user
return get_response(request)
return middleware

View file

@ -15,6 +15,9 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='account', model_name='account',
name='cofprofile', name='cofprofile',
field=models.OneToOneField(to='gestion.Profile', related_name='account_kfet'), field=models.OneToOneField(
to='gestion.Profile',
on_delete=models.CASCADE,
related_name='account_kfet'),
), ),
] ]

View file

@ -1,19 +1,18 @@
configparser==3.5.0 configparser==3.5.0
Django==1.8.* Django==1.11b1
django-autocomplete-light==2.3.3 django-autocomplete-light==2.3.3
django-autoslug==1.9.3 django-autoslug==1.9.3
django-cas-ng==3.5.5 django-cas-ng==3.5.6
django-grappelli==2.8.1 django-recaptcha==1.2.1
django-recaptcha==1.0.5 mysqlclient==1.3.10
mysqlclient==1.3.7 Pillow
Pillow==3.3.0 six
six==1.10.0 unicodecsv
unicodecsv==0.14.1 icalendar
icalendar==3.10
django-bootstrap-form==3.2.1 django-bootstrap-form==3.2.1
asgiref==0.14.0 asgiref==1.0.0
daphne==0.14.3 daphne==1.0.3
asgi-redis==0.14.0 asgi-redis==1.0.0
statistics==1.0.3.5 statistics==1.0.3.5
future==0.15.2 future==0.15.2
django-widget-tweaks==1.4.1 django-widget-tweaks==1.4.1