diff --git a/cof/urls.py b/cof/urls.py
index 5a4a49dc..750107fb 100644
--- a/cof/urls.py
+++ b/cof/urls.py
@@ -16,7 +16,8 @@ from django.contrib.auth import views as django_views
from django_cas_ng import views as django_cas_views
from gestioncof import views as gestioncof_views, csv_views
from gestioncof.urls import export_patterns, petitcours_patterns, \
- surveys_patterns, events_patterns, calendar_patterns
+ surveys_patterns, events_patterns, calendar_patterns, \
+ clubs_patterns
from gestioncof.autocomplete import autocomplete
@@ -38,6 +39,8 @@ urlpatterns = [
url(r'^event/', include(events_patterns)),
# Calendrier
url(r'^calendar/', include(calendar_patterns)),
+ # Clubs
+ url(r'^clubs/', include(clubs_patterns)),
# Authentification
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
name="cof-denied"),
diff --git a/gestioncof/admin.py b/gestioncof/admin.py
index 342317f3..7aedf089 100644
--- a/gestioncof/admin.py
+++ b/gestioncof/admin.py
@@ -4,6 +4,7 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
+from django import forms
from django.contrib import admin
from gestioncof.models import SurveyQuestionAnswer, SurveyQuestion, \
CofProfile, EventOption, EventOptionChoice, Event, Club, CustomMail, \
@@ -232,6 +233,25 @@ class PetitCoursDemandeAdmin(admin.ModelAdmin):
class CustomMailAdmin(admin.ModelAdmin):
search_fields = ('shortname', 'title')
+
+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(SurveyQuestion, SurveyQuestionAdmin)
admin.site.register(Event, EventAdmin)
@@ -239,7 +259,7 @@ admin.site.register(EventOption, EventOptionAdmin)
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
admin.site.register(CofProfile)
-admin.site.register(Club)
+admin.site.register(Club, ClubAdmin)
admin.site.register(CustomMail)
admin.site.register(PetitCoursSubject)
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
diff --git a/gestioncof/forms.py b/gestioncof/forms.py
index 62e47c0e..8a64825f 100644
--- a/gestioncof/forms.py
+++ b/gestioncof/forms.py
@@ -13,7 +13,7 @@ from django.db.models import Max
from django.core.validators import MinLengthValidator
from gestioncof.models import CofProfile, EventCommentValue, \
- CalendarSubscription
+ CalendarSubscription, Club
from gestioncof.widgets import TriStateCheckbox
from gestioncof.shared import lock_table, unlock_table
@@ -392,3 +392,14 @@ class CalendarForm(forms.ModelForm):
model = CalendarSubscription
fields = ['subscribe_to_events', 'subscribe_to_my_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)
diff --git a/gestioncof/migrations/0007_alter_club.py b/gestioncof/migrations/0007_alter_club.py
new file mode 100644
index 00000000..324c59a6
--- /dev/null
+++ b/gestioncof/migrations/0007_alter_club.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('gestioncof', '0006_add_calendar'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='club',
+ name='name',
+ field=models.CharField(unique=True, max_length=200,
+ verbose_name='Nom')
+ ),
+ migrations.AlterField(
+ model_name='club',
+ name='description',
+ field=models.TextField(verbose_name='Description', blank=True)
+ ),
+ migrations.AlterField(
+ model_name='club',
+ name='membres',
+ field=models.ManyToManyField(related_name='clubs',
+ to=settings.AUTH_USER_MODEL,
+ blank=True),
+ ),
+ migrations.AlterField(
+ model_name='club',
+ name='respos',
+ field=models.ManyToManyField(related_name='clubs_geres',
+ to=settings.AUTH_USER_MODEL,
+ blank=True),
+ ),
+ migrations.AlterField(
+ model_name='event',
+ name='start_date',
+ field=models.DateTimeField(null=True,
+ verbose_name='Date de d\xe9but',
+ blank=True),
+ ),
+ ]
diff --git a/gestioncof/models.py b/gestioncof/models.py
index 95837a3a..382a5750 100644
--- a/gestioncof/models.py
+++ b/gestioncof/models.py
@@ -86,10 +86,11 @@ post_save.connect(create_user_profile, sender=User)
@python_2_unicode_compatible
class Club(models.Model):
- name = models.CharField("Nom", max_length=200)
- description = models.TextField("Description")
- respos = models.ManyToManyField(User, related_name="clubs_geres")
- membres = models.ManyToManyField(User, related_name="clubs")
+ 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
diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html
index f476a0dd..0907adc6 100644
--- a/gestioncof/templates/home.html
+++ b/gestioncof/templates/home.html
@@ -70,6 +70,7 @@
Administration générale
Demandes de petits cours
Inscription d'un nouveau membre
+ Gestion des clubs
Évènements & Sondages
diff --git a/gestioncof/templates/liste_clubs.html b/gestioncof/templates/liste_clubs.html
new file mode 100644
index 00000000..c248a7a6
--- /dev/null
+++ b/gestioncof/templates/liste_clubs.html
@@ -0,0 +1,25 @@
+{% extends "base_title.html" %}
+
+{% block page_size %}col-sm-8{% endblock %}
+
+{% block realcontent %}
+Clubs enregistrés sur GestioCOF
+
+{% endblock %}
diff --git a/gestioncof/templates/membres_clubs.html b/gestioncof/templates/membres_clubs.html
new file mode 100644
index 00000000..8c932ed5
--- /dev/null
+++ b/gestioncof/templates/membres_clubs.html
@@ -0,0 +1,41 @@
+{% extends "base_title.html" %}
+
+
+{% block realcontent %}
+{{ club }}
+
+
+{% if club.respos.exists %}
+Respo{{ club.respos.all|pluralize }}
+
+{% for member in club.respos.all %}
+
+ {{ member }} |
+ {{ member.email }} |
+ |
+
+{% endfor %}
+
+{% else %}
+Pas de respo
+{% endif %}
+
+
+{% if club.membres.exists %}
+Liste des membres
+
+{% for member in members_no_respo %}
+
+ {{ member }} |
+ {{ member.email }} |
+ |
+
+{% endfor %}
+
+{% else %}
+Ce club ne comporte actuellement aucun membre.
+{% endif %}
+
+{% endblock %}
diff --git a/gestioncof/templates/registration_form.html b/gestioncof/templates/registration_form.html
index 1eb16393..8668152b 100644
--- a/gestioncof/templates/registration_form.html
+++ b/gestioncof/templates/registration_form.html
@@ -13,6 +13,10 @@
{{ user_form | bootstrap }}
{{ profile_form | bootstrap }}
+
+
+ {{ clubs_form | bootstrap }}
+
{{ event_formset.management_form }}
{% for event_form in event_formset %}
diff --git a/gestioncof/urls.py b/gestioncof/urls.py
index 89cd5aa8..ad108005 100644
--- a/gestioncof/urls.py
+++ b/gestioncof/urls.py
@@ -52,3 +52,10 @@ calendar_patterns = [
url(r'^(?P[a-z0-9-]+)/calendar.ics$',
'gestioncof.views.calendar_ics')
]
+
+clubs_patterns = [
+ url(r'^membres/(?P\w+)', views.membres_club, name='membres-club'),
+ url(r'^liste', views.liste_clubs, name='liste-clubs'),
+ url(r'^change_respo/(?P\w+)/(?P\d+)',
+ views.change_respo, name='change-respo'),
+]
diff --git a/gestioncof/views.py b/gestioncof/views.py
index be3a51d4..3148308a 100644
--- a/gestioncof/views.py
+++ b/gestioncof/views.py
@@ -10,7 +10,7 @@ from datetime import timedelta
from icalendar import Calendar, Event as Vevent
from django.shortcuts import redirect, get_object_or_404, render
-from django.http import Http404, HttpResponse
+from django.http import Http404, HttpResponse, HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as django_login_view
from django.contrib.auth.models import User
@@ -24,12 +24,12 @@ from gestioncof.models import Event, EventRegistration, EventOption, \
from gestioncof.models import EventCommentField, EventCommentValue, \
CalendarSubscription
from gestioncof.shared import send_custom_mail
-from gestioncof.models import CofProfile, Clipper
+from gestioncof.models import CofProfile, Clipper, Club
from gestioncof.decorators import buro_required, cof_required
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
RegistrationProfileForm, EventForm, CalendarForm, EventFormset, \
- RegistrationPassUserForm
+ RegistrationPassUserForm, ClubsForm
from bda.models import Tirage, Spectacle
@@ -344,8 +344,9 @@ def registration_form2(request, login_clipper=None, username=None):
profile_form = RegistrationProfileForm(initial={
'login_clipper': login_clipper})
registration_set_ro_fields(user_form, profile_form)
- # events
+ # events & clubs
event_formset = EventFormset(events=events, prefix='events')
+ clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
if username:
member = get_object_or_404(User, username=username)
(profile, _) = CofProfile.objects.get_or_create(user=member)
@@ -364,16 +365,21 @@ def registration_form2(request, login_clipper=None, username=None):
event_formset = EventFormset(
events=events, prefix='events',
current_registrations=current_registrations)
+ # Clubs
+ clubs_form = ClubsForm(initial={'clubs': member.clubs.all()})
elif not login_clipper:
# new user
user_form = RegistrationPassUserForm()
user_form.force_long_username()
profile_form = RegistrationProfileForm()
event_formset = EventFormset(events=events, prefix='events')
+ clubs_form = ClubsForm()
return render(request, "registration_form.html",
- {"user_form": user_form, "profile_form": profile_form,
- "member": member, "login_clipper": login_clipper,
- "event_formset": event_formset})
+ {"member": member, "login_clipper": login_clipper,
+ "user_form": user_form,
+ "profile_form": profile_form,
+ "event_formset": event_formset,
+ "clubs_form": clubs_form})
@buro_required
@@ -396,6 +402,7 @@ def registration(request):
else:
user_form = RegistrationUserForm(request_dict)
profile_form = RegistrationProfileForm(request_dict)
+ clubs_form = ClubsForm(request_dict)
events = Event.objects.filter(old=False).all()
event_formset = EventFormset(events=events, data=request_dict,
prefix='events')
@@ -425,10 +432,13 @@ def registration(request):
# Maintenant on remplit le formulaire de profil
profile_form = RegistrationProfileForm(request_dict,
instance=profile)
- if profile_form.is_valid() and event_formset.is_valid():
+ if (profile_form.is_valid() and event_formset.is_valid()
+ and clubs_form.is_valid()):
+ # Enregistrement du profil
profile = profile_form.save()
if profile.is_cof and not was_cof:
send_custom_mail(member, "bienvenue")
+ # Enregistrement des inscriptions aux événements
for form in event_formset:
if 'status' not in form.cleaned_data:
form.cleaned_data['status'] = 'no'
@@ -461,6 +471,11 @@ def registration(request):
comments = field.default
send_custom_mail(member, "mega",
{"remarques": comments})
+ # Enregistrement des inscriptions aux clubs
+ member.clubs.clear()
+ for club in clubs_form.cleaned_data['clubs']:
+ club.membres.add(member)
+ club.save()
success = True
return render(request, "registration_post.html",
{"success": success,
@@ -468,11 +483,56 @@ def registration(request):
"profile_form": profile_form,
"member": member,
"login_clipper": login_clipper,
- "event_formset": event_formset})
+ "event_formset": event_formset,
+ "clubs_form": clubs_form})
else:
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('Permission denied
')
+ 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
def export_members(request):
response = HttpResponse(content_type='text/csv')