Merge branch 'master' into Production

This commit is contained in:
Martin Pépin 2017-09-09 22:03:32 +02:00
commit 937a485704
174 changed files with 8315 additions and 3617 deletions

View file

@ -0,0 +1 @@
default_app_config = 'gestioncof.apps.GestioncofConfig'

View file

@ -1,9 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django import forms
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
@ -18,13 +12,12 @@ from django.contrib.auth.admin import UserAdmin
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.db.models import Q
import django.utils.six as six
import autocomplete_light
def add_link_field(target_model='', field='', link_text=six.text_type,
desc_text=six.text_type):
def add_link_field(target_model='', field='', link_text=str,
desc_text=str):
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
@ -139,7 +132,6 @@ def ProfileInfo(field, short_description, boolean=False):
User.profile_login_clipper = FkeyLookup("profile__login_clipper",
"Login clipper")
User.profile_num = FkeyLookup("profile__num", "Numéro")
User.profile_phone = ProfileInfo("phone", "Téléphone")
User.profile_occupation = ProfileInfo("occupation", "Occupation")
User.profile_departement = ProfileInfo("departement", "Departement")
@ -166,10 +158,12 @@ class UserProfileAdmin(UserAdmin):
is_cof.short_description = 'Membre du COF'
is_cof.boolean = True
list_display = ('profile_num',) + UserAdmin.list_display \
list_display = (
UserAdmin.list_display
+ ('profile_login_clipper', 'profile_phone', 'profile_occupation',
'profile_mailing_cof', 'profile_mailing_bda',
'profile_mailing_bda_revente', 'is_cof', 'is_buro', )
)
list_display_links = ('username', 'email', 'first_name', 'last_name')
list_filter = UserAdmin.list_filter \
+ ('profile__is_cof', 'profile__is_buro', 'profile__mailing_cof',
@ -215,21 +209,17 @@ class UserProfileAdmin(UserAdmin):
# FIXME: This is absolutely horrible.
def user_unicode(self):
def user_str(self):
if self.first_name and self.last_name:
return "%s %s (%s)" % (self.first_name, self.last_name, self.username)
return "{} ({})".format(self.get_full_name(), self.username)
else:
return self.username
if six.PY2:
User.__unicode__ = user_unicode
else:
User.__str__ = user_unicode
User.__str__ = user_str
class EventRegistrationAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(EventRegistration, exclude=[])
list_display = ('__unicode__' if six.PY2 else '__str__', 'event', 'user',
'paid')
list_display = ('__str__', 'event', 'user', 'paid')
list_filter = ('paid',)
search_fields = ('user__username', 'user__first_name', 'user__last_name',
'user__email', 'event__title')

15
gestioncof/apps.py Normal file
View file

@ -0,0 +1,15 @@
from django.apps import AppConfig
class GestioncofConfig(AppConfig):
name = 'gestioncof'
verbose_name = "Gestion des adhérents du COF"
def ready(self):
from . import signals
self.register_config()
def register_config(self):
import djconfig
from .forms import GestioncofConfigForm
djconfig.register(GestioncofConfigForm)

View file

@ -1,20 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.formsets import BaseFormSet, formset_factory
from django.db.models import Max
from djconfig.forms import ConfigForm
from gestioncof.models import CofProfile, EventCommentValue, \
CalendarSubscription, Club
from gestioncof.widgets import TriStateCheckbox
from gestioncof.shared import lock_table, unlock_table
from bda.models import Spectacle
@ -239,7 +233,6 @@ class RegistrationProfileForm(forms.ModelForm):
self.fields['mailing_cof'].initial = True
self.fields['mailing_bda'].initial = True
self.fields['mailing_bda_revente'].initial = True
self.fields['num'].widget.attrs['readonly'] = True
self.fields.keyOrder = [
'login_clipper',
@ -247,7 +240,6 @@ class RegistrationProfileForm(forms.ModelForm):
'occupation',
'departement',
'is_cof',
'num',
'type_cotiz',
'mailing_cof',
'mailing_bda',
@ -255,24 +247,9 @@ class RegistrationProfileForm(forms.ModelForm):
'comments'
]
def save(self, *args, **kw):
instance = super(RegistrationProfileForm, self).save(*args, **kw)
if instance.is_cof and not instance.num:
# Generate new number
try:
lock_table(CofProfile)
aggregate = CofProfile.objects.aggregate(Max('num'))
instance.num = aggregate['num__max'] + 1
instance.save()
self.cleaned_data['num'] = instance.num
self.data['num'] = instance.num
finally:
unlock_table(CofProfile)
return instance
class Meta:
model = CofProfile
fields = ("login_clipper", "num", "phone", "occupation",
fields = ("login_clipper", "phone", "occupation",
"departement", "is_cof", "type_cotiz", "mailing_cof",
"mailing_bda", "mailing_bda_revente", "comments")
@ -399,3 +376,16 @@ class ClubsForm(forms.Form):
queryset=Club.objects.all(),
widget=forms.CheckboxSelectMultiple,
required=False)
# ---
# Announcements banner
# TODO: move this to the `gestion` app once the supportBDS branch is merged
# ---
class GestioncofConfigForm(ConfigForm):
gestion_banner = forms.CharField(
label=_("Announcements banner"),
help_text=_("An empty banner disables annoucements"),
max_length=2048
)

View file

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0010_delete_custommail'),
]
operations = [
migrations.RemoveField(
model_name='cofprofile',
name='num',
),
]

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0011_remove_cofprofile_num'),
('gestioncof', '0011_longer_clippers'),
]
operations = [
]

View file

@ -1,11 +1,7 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.dispatch import receiver
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible
import django.utils.six as six
from django.db.models.signals import post_save, post_delete
from gestioncof.petits_cours_models import choices_length
@ -35,14 +31,12 @@ TYPE_COMMENT_FIELD = (
)
@python_2_unicode_compatible
class CofProfile(models.Model):
user = models.OneToOneField(User, related_name="profile")
login_clipper = models.CharField(
"Login clipper", max_length=32, blank=True
)
is_cof = models.BooleanField("Membre du COF", default=False)
num = models.IntegerField("Numéro d'adhérent", blank=True, default=0)
phone = models.CharField("Téléphone", max_length=20, blank=True)
occupation = models.CharField(_("Occupation"),
default="1A",
@ -74,7 +68,7 @@ class CofProfile(models.Model):
verbose_name_plural = "Profils COF"
def __str__(self):
return six.text_type(self.user.username)
return self.user.username
@receiver(post_save, sender=User)
@ -88,7 +82,6 @@ def post_delete_user(sender, instance, *args, **kwargs):
instance.user.delete()
@python_2_unicode_compatible
class Club(models.Model):
name = models.CharField("Nom", max_length=200, unique=True)
description = models.TextField("Description", blank=True)
@ -100,7 +93,6 @@ class Club(models.Model):
return self.name
@python_2_unicode_compatible
class Event(models.Model):
title = models.CharField("Titre", max_length=200)
location = models.CharField("Lieu", max_length=200)
@ -117,10 +109,9 @@ class Event(models.Model):
verbose_name = "Événement"
def __str__(self):
return six.text_type(self.title)
return self.title
@python_2_unicode_compatible
class EventCommentField(models.Model):
event = models.ForeignKey(Event, related_name="commentfields")
name = models.CharField("Champ", max_length=200)
@ -132,10 +123,9 @@ class EventCommentField(models.Model):
verbose_name = "Champ"
def __str__(self):
return six.text_type(self.name)
return self.name
@python_2_unicode_compatible
class EventCommentValue(models.Model):
commentfield = models.ForeignKey(EventCommentField, related_name="values")
registration = models.ForeignKey("EventRegistration",
@ -146,7 +136,6 @@ class EventCommentValue(models.Model):
return "Commentaire de %s" % self.commentfield
@python_2_unicode_compatible
class EventOption(models.Model):
event = models.ForeignKey(Event, related_name="options")
name = models.CharField("Option", max_length=200)
@ -156,10 +145,9 @@ class EventOption(models.Model):
verbose_name = "Option"
def __str__(self):
return six.text_type(self.name)
return self.name
@python_2_unicode_compatible
class EventOptionChoice(models.Model):
event_option = models.ForeignKey(EventOption, related_name="choices")
value = models.CharField("Valeur", max_length=200)
@ -169,10 +157,9 @@ class EventOptionChoice(models.Model):
verbose_name_plural = "Choix"
def __str__(self):
return six.text_type(self.value)
return self.value
@python_2_unicode_compatible
class EventRegistration(models.Model):
user = models.ForeignKey(User)
event = models.ForeignKey(Event)
@ -186,11 +173,9 @@ class EventRegistration(models.Model):
unique_together = ("user", "event")
def __str__(self):
return "Inscription de %s à %s" % (six.text_type(self.user),
six.text_type(self.event.title))
return "Inscription de {} à {}".format(self.user, self.event.title)
@python_2_unicode_compatible
class Survey(models.Model):
title = models.CharField("Titre", max_length=200)
details = models.TextField("Détails", blank=True)
@ -201,10 +186,9 @@ class Survey(models.Model):
verbose_name = "Sondage"
def __str__(self):
return six.text_type(self.title)
return self.title
@python_2_unicode_compatible
class SurveyQuestion(models.Model):
survey = models.ForeignKey(Survey, related_name="questions")
question = models.CharField("Question", max_length=200)
@ -214,10 +198,9 @@ class SurveyQuestion(models.Model):
verbose_name = "Question"
def __str__(self):
return six.text_type(self.question)
return self.question
@python_2_unicode_compatible
class SurveyQuestionAnswer(models.Model):
survey_question = models.ForeignKey(SurveyQuestion, related_name="answers")
answer = models.CharField("Réponse", max_length=200)
@ -226,10 +209,9 @@ class SurveyQuestionAnswer(models.Model):
verbose_name = "Réponse"
def __str__(self):
return six.text_type(self.answer)
return self.answer
@python_2_unicode_compatible
class SurveyAnswer(models.Model):
user = models.ForeignKey(User)
survey = models.ForeignKey(Survey)
@ -246,7 +228,6 @@ class SurveyAnswer(models.Model):
self.survey.title)
@python_2_unicode_compatible
class CalendarSubscription(models.Model):
token = models.UUIDField()
user = models.OneToOneField(User)

View file

@ -12,28 +12,34 @@ from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import transaction
from gestioncof.models import CofProfile
from gestioncof.petits_cours_models import (
PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter,
PetitCoursAbility, PetitCoursSubject
PetitCoursAbility
)
from gestioncof.petits_cours_forms import DemandeForm, MatieresFormSet
from gestioncof.decorators import buro_required
from gestioncof.shared import lock_table, unlock_tables
class DemandeListView(ListView):
model = PetitCoursDemande
queryset = (
PetitCoursDemande.objects
.prefetch_related('matieres')
.order_by('traitee', '-id')
)
template_name = "petits_cours_demandes_list.html"
paginate_by = 20
def get_queryset(self):
return PetitCoursDemande.objects.order_by('traitee', '-id').all()
class DemandeDetailView(DetailView):
model = PetitCoursDemande
queryset = (
PetitCoursDemande.objects
.prefetch_related('petitcoursattribution_set',
'matieres')
)
template_name = "gestioncof/details_demande_petit_cours.html"
context_object_name = "demande"
@ -268,17 +274,17 @@ def _traitement_post(request, demande):
headers={'Reply-To': replyto}))
connection = mail.get_connection(fail_silently=False)
connection.send_messages(mails_to_send)
lock_table(PetitCoursAttributionCounter, PetitCoursAttribution, User)
for matiere in proposals:
for rank, user in enumerate(proposals[matiere]):
counter = PetitCoursAttributionCounter.objects.get(user=user,
matiere=matiere)
counter.count += 1
counter.save()
attrib = PetitCoursAttribution(user=user, matiere=matiere,
demande=demande, rank=rank + 1)
attrib.save()
unlock_tables()
with transaction.atomic():
for matiere in proposals:
for rank, user in enumerate(proposals[matiere]):
counter = PetitCoursAttributionCounter.objects.get(
user=user, matiere=matiere
)
counter.count += 1
counter.save()
attrib = PetitCoursAttribution(user=user, matiere=matiere,
demande=demande, rank=rank + 1)
attrib.save()
demande.traitee = True
demande.traitee_par = request.user
demande.processed = datetime.now()
@ -303,17 +309,15 @@ def inscription(request):
profile.petits_cours_accept = "receive_proposals" in request.POST
profile.petits_cours_remarques = request.POST["remarques"]
profile.save()
lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User,
PetitCoursSubject)
abilities = (
PetitCoursAbility.objects.filter(user=request.user).all()
)
for ability in abilities:
PetitCoursAttributionCounter.get_uptodate(
ability.user,
ability.matiere
with transaction.atomic():
abilities = (
PetitCoursAbility.objects.filter(user=request.user).all()
)
unlock_tables()
for ability in abilities:
PetitCoursAttributionCounter.get_uptodate(
ability.user,
ability.matiere
)
success = True
formset = MatieresFormSet(instance=request.user)
else:

View file

@ -1,69 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.contrib.sites.models import Site
from django.conf import settings
from django.contrib.sites.models import Site
from django_cas_ng.backends import CASBackend
from django_cas_ng.utils import get_cas_client
from django.contrib.auth import get_user_model
from django.db import connection
from gestioncof.models import CofProfile
User = get_user_model()
class COFCASBackend(CASBackend):
def authenticate_cas(self, ticket, service, request):
"""Verifies CAS ticket and gets or creates User object"""
client = get_cas_client(service_url=service)
username, attributes, _ = client.verify_ticket(ticket)
if attributes:
request.session['attributes'] = attributes
if not username:
return None
def clean_username(self, username):
# Le CAS de l'ENS accepte les logins avec des espaces au début
# et à la fin, ainsi quavec une casse variable. On normalise pour
# éviter les doublons.
username = username.strip().lower()
return username.strip().lower()
profiles = CofProfile.objects.filter(login_clipper=username)
if len(profiles) > 0:
profile = profiles.order_by('-is_cof')[0]
user = profile.user
return user
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# user will have an "unusable" password
user = User.objects.create_user(username, '')
user.save()
return user
def authenticate(self, ticket, service, request):
"""Authenticates CAS ticket and retrieves user data"""
user = self.authenticate_cas(ticket, service, request)
if user is None:
return user
try:
profile = user.profile
except CofProfile.DoesNotExist:
profile, created = CofProfile.objects.get_or_create(user=user)
profile.save()
if not profile.login_clipper:
profile.login_clipper = user.username
profile.save()
if not user.email:
user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper
user.save()
if profile.is_buro and not user.is_staff:
user.is_staff = True
user.save()
def configure_user(self, user):
clipper = user.username
user.profile.login_clipper = clipper
user.profile.save()
user.email = settings.CAS_EMAIL_FORMAT % clipper
user.save()
return user
@ -74,25 +30,3 @@ def context_processor(request):
"site": Site.objects.get_current(),
}
return data
def lock_table(*models):
query = "LOCK TABLES "
for i, model in enumerate(models):
table = model._meta.db_table
if i > 0:
query += ", "
query += "%s WRITE" % table
cursor = connection.cursor()
cursor.execute(query)
row = cursor.fetchone()
return row
def unlock_tables(*models):
cursor = connection.cursor()
cursor.execute("UNLOCK TABLES")
row = cursor.fetchone()
return row
unlock_table = unlock_tables

23
gestioncof/signals.py Normal file
View file

@ -0,0 +1,23 @@
from django.contrib import messages
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django_cas_ng.signals import cas_user_authenticated
@receiver(user_logged_in)
def messages_on_out_login(request, user, **kwargs):
if user.backend.startswith('django.contrib.auth'):
msg = _('Connexion à GestioCOF réussie. Bienvenue {}.').format(
user.get_short_name(),
)
messages.success(request, msg)
@receiver(cas_user_authenticated)
def mesagges_on_cas_login(request, user, **kwargs):
msg = _('Connexion à GestioCOF par CAS réussie. Bienvenue {}.').format(
user.get_short_name(),
)
messages.success(request, msg)

View file

@ -40,8 +40,9 @@ a {
background: transparent;
}
div.empty-form {
padding-bottom: 2em;
}
a:hover {
color: #444;
@ -341,10 +342,12 @@ fieldset legend {
font-weight: 700;
font-size: large;
color:#DE826B;
padding-bottom: .5em;
}
#main-content h4 {
color:#DE826B;
padding-bottom: .5em;
}
#main-content h2,
@ -778,6 +781,17 @@ header .open > .dropdown-toggle.btn-default {
border-color: white;
}
/* Announcements banner ------------------ */
#banner {
background-color: #d86b01;
width: 100%;
text-align: center;
padding: 10px;
color: white;
font-size: larger;
}
/* FORMS --------------------------------- */

View file

@ -8,13 +8,13 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{# CSS #}
{# CSS #}
<link type="text/css" rel="stylesheet" href="{% static "css/bootstrap.min.css" %}" />
<link type="text/css" rel="stylesheet" href="{% static "css/cof.css" %}" />
<link href="https://fonts.googleapis.com/css?family=Dosis|Dosis:700|Raleway|Roboto:300,300i,700" rel="stylesheet">
<link rel="stylesheet" href="{% static "font-awesome/css/font-awesome.min.css" %}">
{# JS #}
{# JS #}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
{% block extra_head %}{% endblock %}

View file

@ -0,0 +1,23 @@
{% extends "base_title.html" %}
{% load bootstrap %}
{% load i18n %}
{% block page_size %}col-sm-8{%endblock%}
{% block realcontent %}
<h2>{% trans "Global configuration" %}</h2>
<form id="profile form-horizontal" method="post" action="">
<div class="row" style="margin: 0 15%;">
{% csrf_token %}
<fieldset"center-block">
{% for field in form %}
{{ field | bootstrap }}
{% endfor %}
</fieldset>
</div>
<div class="form-actions">
<input type="submit" class="btn btn-primary pull-right"
value={% trans "Save" %} />
</div>
</form>
{% endblock %}

View file

@ -16,6 +16,14 @@
<h2 class="member-status">{% if user.first_name %}{{ user.first_name }}{% else %}<tt>{{ user.username }}</tt>{% endif %}, {% if user.profile.is_cof %}<tt class="user-is-cof">au COF{% else %}<tt class="user-is-not-cof">non-COF{% endif %}</tt></h2>
</div><!-- /.container -->
</header>
{% if config.gestion_banner %}
<div id="banner" class="container">
<span class="glyphicon glyphicon-bullhorn"></span>
<span>{{ config.gestion_banner }}</span>
</div>
{% endif %}
{% if messages %}
{% for message in messages %}
<div class="messages">

View file

@ -1,4 +1,5 @@
{% extends "gestioncof/base_header.html" %}
{% load wagtailcore_tags %}
{% block homelink %}
{% endblock %}
@ -55,7 +56,8 @@
<h3 class="block-title">K-Fêt<span class="pull-right"><i class="fa fa-coffee"></i></span></h3>
<div class="hm-block">
<ul>
<li><a href="{% url "kfet.home" %}">Page d'accueil</a></li>
{# TODO: Since Django 1.9, we can store result with "as", allowing proper value management (if None) #}
<li><a href="{% slugurl "k-fet" %}">Page d'accueil</a></li>
<li><a href="https://www.cof.ens.fr/k-fet/calendrier">Calendrier</a></li>
{% if perms.kfet.is_team %}
<li><a href="{% url 'kfet.kpsul' %}">K-Psul</a></li>

View file

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
import unicodecsv
import uuid
from datetime import timedelta
@ -9,12 +7,18 @@ from custommail.shortcuts import send_custom_mail
from django.shortcuts import redirect, get_object_or_404, render
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.views import (
login as django_login_view, logout as django_logout_view,
)
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse_lazy
from django.views.generic import FormView
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.contrib import messages
import django.utils.six as six
from django_cas_ng.views import logout as cas_logout_view
from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
SurveyQuestionAnswer
@ -24,10 +28,11 @@ from gestioncof.models import EventCommentField, EventCommentValue, \
CalendarSubscription
from gestioncof.models import CofProfile, Club
from gestioncof.decorators import buro_required, cof_required
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
RegistrationProfileForm, EventForm, CalendarForm, EventFormset, \
RegistrationPassUserForm, ClubsForm
from gestioncof.forms import (
UserProfileForm, EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm,
RegistrationUserForm, RegistrationProfileForm, EventForm, CalendarForm,
EventFormset, RegistrationPassUserForm, ClubsForm, GestioncofConfigForm
)
from bda.models import Tirage, Spectacle
@ -81,20 +86,29 @@ def login_ext(request):
@login_required
def logout(request):
try:
profile = request.user.profile
except CofProfile.DoesNotExist:
profile, created = CofProfile.objects.get_or_create(user=request.user)
if profile.login_clipper:
return redirect("django_cas_ng.views.logout")
def logout(request, next_page=None):
if next_page is None:
next_page = request.GET.get('next', None)
profile = getattr(request.user, 'profile', None)
if profile and profile.login_clipper:
msg = _('Déconnexion de GestioCOF et CAS réussie. À bientôt {}.')
logout_view = cas_logout_view
else:
return redirect("django.contrib.auth.views.logout")
msg = _('Déconnexion de GestioCOF réussie. À bientôt {}.')
logout_view = django_logout_view
messages.success(request, msg.format(request.user.get_short_name()))
return logout_view(request, next_page=next_page)
@login_required
def survey(request, survey_id):
survey = get_object_or_404(Survey, id=survey_id)
survey = get_object_or_404(
Survey.objects.prefetch_related('questions', 'questions__answers'),
id=survey_id,
)
if not survey.survey_open or survey.old:
raise Http404
success = False
@ -399,12 +413,8 @@ def registration_form2(request, login_clipper=None, username=None,
def registration(request):
if request.POST:
request_dict = request.POST.copy()
# num ne peut pas être défini manuellement
if "num" in request_dict:
del request_dict["num"]
member = None
login_clipper = None
success = False
# -----
# Remplissage des formulaires
@ -439,7 +449,6 @@ def registration(request):
member = user_form.save()
profile, _ = CofProfile.objects.get_or_create(user=member)
was_cof = profile.is_cof
request_dict["num"] = profile.num
# Maintenant on remplit le formulaire de profil
profile_form = RegistrationProfileForm(request_dict,
instance=profile)
@ -493,16 +502,18 @@ def registration(request):
for club in clubs_form.cleaned_data['clubs']:
club.membres.add(member)
club.save()
success = True
# Messages
if success:
msg = ("L'inscription de {:s} (<tt>{:s}</tt>) a été "
"enregistrée avec succès"
.format(member.get_full_name(), member.email))
if member.profile.is_cof:
msg += "Il est désormais membre du COF n°{:d} !".format(
member.profile.num)
messages.success(request, msg, extra_tags='safe')
# ---
# Success
# ---
msg = ("L'inscription de {:s} (<tt>{:s}</tt>) a été "
"enregistrée avec succès."
.format(member.get_full_name(), member.email))
if profile.is_cof:
msg += "\nIl est désormais membre du COF n°{:d} !".format(
member.profile.id)
messages.success(request, msg, extra_tags='safe')
return render(request, "gestioncof/registration_post.html",
{"user_form": user_form,
"profile_form": profile_form,
@ -566,10 +577,10 @@ def export_members(request):
writer = unicodecsv.writer(response)
for profile in CofProfile.objects.filter(is_cof=True).all():
user = profile.user
bits = [profile.num, user.username, user.first_name, user.last_name,
bits = [profile.id, user.username, user.first_name, user.last_name,
user.email, profile.phone, profile.occupation,
profile.departement, profile.type_cotiz]
writer.writerow([six.text_type(bit) for bit in bits])
writer.writerow([str(bit) for bit in bits])
return response
@ -585,10 +596,10 @@ def csv_export_mega(filename, qs):
comments = "---".join(
[comment.content for comment in reg.comments.all()])
bits = [user.username, user.first_name, user.last_name, user.email,
profile.phone, profile.num,
profile.phone, profile.id,
profile.comments if profile.comments else "", comments]
writer.writerow([six.text_type(bit) for bit in bits])
writer.writerow([str(bit) for bit in bits])
return response
@ -607,8 +618,8 @@ def export_mega_remarksonly(request):
user = reg.user
profile = user.profile
bits = [user.username, user.first_name, user.last_name, user.email,
profile.phone, profile.num, profile.comments, val.content]
writer.writerow([six.text_type(bit) for bit in bits])
profile.phone, profile.id, profile.comments, val.content]
writer.writerow([str(bit) for bit in bits])
return response
@ -760,3 +771,18 @@ def calendar_ics(request, token):
response = HttpResponse(content=vcal.to_ical())
response['Content-Type'] = "text/calendar"
return response
class ConfigUpdate(FormView):
form_class = GestioncofConfigForm
template_name = "gestioncof/banner_update.html"
success_url = reverse_lazy("home")
def dispatch(self, request, *args, **kwargs):
if request.user is None or not request.user.is_superuser:
raise Http404
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form):
form.save()
return super().form_valid(form)