kpsul/gestioncof/views.py
Martin Pépin 5b0b60fadb Meilleure inscription des extés
Lors de la création d'un compte exté via la vue `/registration` (i.e. compte
non associé à un clipper), deux champs sont ajoutés au formulaire pour la
création d'un mot de passe.

Il est toujours possible de changer ce mot de passe via l'admin s'il est perdu
par l'utilisateur.
2016-08-17 15:34:01 +02:00

666 lines
27 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import unicodecsv
import uuid
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.contrib.auth.decorators import login_required
from django.contrib.auth.views import login as django_login_view
from django.contrib.auth.models import User
from django.utils import timezone
import django.utils.six as six
from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
SurveyQuestionAnswer
from gestioncof.models import Event, EventRegistration, EventOption, \
EventOptionChoice
from gestioncof.models import EventCommentField, EventCommentValue, \
CalendarSubscription
from gestioncof.shared import send_custom_mail
from gestioncof.models import CofProfile, Clipper
from gestioncof.decorators import buro_required, cof_required
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
RegistrationProfileForm, EventForm, CalendarForm, EventFormset, \
RegistrationPassUserForm
from bda.models import Tirage, Spectacle
@login_required
def home(request):
data = {"surveys": Survey.objects.filter(old=False).all(),
"events": Event.objects.filter(old=False).all(),
"open_surveys":
Survey.objects.filter(survey_open=True, old=False).all(),
"open_events":
Event.objects.filter(registration_open=True, old=False).all(),
"open_tirages": Tirage.objects.filter(active=True).all(),
"now": timezone.now()}
return render(request, "home.html", data)
def login(request):
if request.user.is_authenticated():
return redirect("gestioncof.views.home")
context = {}
if request.method == "GET" and 'next' in request.GET:
context['next'] = request.GET['next']
return render(request, "login_switch.html", context)
def login_ext(request):
if request.method == "POST" and "username" in request.POST:
try:
user = User.objects.get(username=request.POST["username"])
if not user.has_usable_password() or user.password in ("", "!"):
profile, created = CofProfile.objects.get_or_create(user=user)
if profile.login_clipper:
return render(request, "error.html",
{"error_type": "use_clipper_login"})
else:
return render(request, "error.html",
{"error_type": "no_password"})
except User.DoesNotExist:
pass
context = {}
if request.method == "GET" and 'next' in request.GET:
context['next'] = request.GET['next']
if request.method == "POST" and 'next' in request.POST:
context['next'] = request.POST['next']
return django_login_view(request, template_name='login.html',
extra_context=context)
@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")
else:
return redirect("django.contrib.auth.views.logout")
@login_required
def survey(request, survey_id):
survey = get_object_or_404(Survey, id=survey_id)
if not survey.survey_open:
raise Http404
success = False
deleted = False
if request.method == "POST":
form = SurveyForm(request.POST, survey=survey)
if request.POST.get('delete'):
try:
current_answer = SurveyAnswer.objects.get(user=request.user,
survey=survey)
current_answer.delete()
current_answer = None
except SurveyAnswer.DoesNotExist:
current_answer = None
form = SurveyForm(survey=survey)
success = True
deleted = True
else:
if form.is_valid():
all_answers = []
for question_id, answers_ids in form.answers():
question = get_object_or_404(SurveyQuestion,
id=question_id,
survey=survey)
if type(answers_ids) != list:
answers_ids = [answers_ids]
if not question.multi_answers and len(answers_ids) > 1:
raise Http404
for answer_id in answers_ids:
if not answer_id:
continue
answer_id = int(answer_id)
answer = SurveyQuestionAnswer.objects.get(
id=answer_id,
survey_question=question)
all_answers.append(answer)
try:
current_answer = SurveyAnswer.objects.get(
user=request.user, survey=survey)
except SurveyAnswer.DoesNotExist:
current_answer = SurveyAnswer(user=request.user,
survey=survey)
current_answer.save()
current_answer.answers = all_answers
current_answer.save()
success = True
else:
try:
current_answer = SurveyAnswer.objects.get(user=request.user,
survey=survey)
form = SurveyForm(survey=survey,
current_answers=current_answer.answers)
except SurveyAnswer.DoesNotExist:
current_answer = None
form = SurveyForm(survey=survey)
return render(request, "survey.html", {"survey": survey, "form": form,
"success": success,
"deleted": deleted,
"current_answer": current_answer})
def get_event_form_choices(event, form):
all_choices = []
for option_id, choices_ids in form.choices():
option = get_object_or_404(EventOption, id=option_id,
event=event)
if type(choices_ids) != list:
choices_ids = [choices_ids]
if not option.multi_choices and len(choices_ids) > 1:
raise Http404
for choice_id in choices_ids:
if not choice_id:
continue
choice_id = int(choice_id)
choice = EventOptionChoice.objects.get(
id=choice_id,
event_option=option)
all_choices.append(choice)
return all_choices
def update_event_form_comments(event, form, registration):
for commentfield_id, value in form.comments():
field = get_object_or_404(EventCommentField, id=commentfield_id,
event=event)
if value == field.default:
continue
(storage, _) = EventCommentValue.objects.get_or_create(
commentfield=field,
registration=registration)
storage.content = value
storage.save()
@login_required
def event(request, event_id):
event = get_object_or_404(Event, id=event_id)
if (not event.registration_open) or event.old:
raise Http404
success = False
if request.method == "POST":
form = EventForm(request.POST, event=event)
if form.is_valid():
all_choices = get_event_form_choices(event, form)
(current_registration, _) = \
EventRegistration.objects.get_or_create(user=request.user,
event=event)
current_registration.options = all_choices
current_registration.save()
success = True
else:
try:
current_registration = \
EventRegistration.objects.get(user=request.user, event=event)
form = EventForm(event=event,
current_choices=current_registration.options)
except EventRegistration.DoesNotExist:
form = EventForm(event=event)
return render(request, "event.html",
{"event": event, "form": form, "success": success})
def clean_post_for_status(initial):
d = initial.copy()
for k, v in d.items():
if k.startswith("id_"):
del d[k]
d[k[3:]] = v
return d
@buro_required
def event_status(request, event_id):
event = get_object_or_404(Event, id=event_id)
registrations_query = EventRegistration.objects.filter(event=event)
post_data = clean_post_for_status(request.POST)
form = EventStatusFilterForm(post_data or None, event=event)
if form.is_valid():
for option_id, choice_id, value in form.filters():
if option_id == "has_paid":
if value == "yes":
registrations_query = registrations_query.filter(paid=True)
elif value == "no":
registrations_query = registrations_query.filter(
paid=False)
continue
choice = get_object_or_404(EventOptionChoice, id=choice_id,
event_option__id=option_id)
if value == "none":
continue
if value == "yes":
registrations_query = registrations_query.filter(
options__id__exact=choice.id)
elif value == "no":
registrations_query = registrations_query.exclude(
options__id__exact=choice.id)
user_choices = registrations_query.prefetch_related("user").all()
options = EventOption.objects.filter(event=event).all()
choices_count = {}
for option in options:
for choice in option.choices.all():
choices_count[choice.id] = 0
for user_choice in user_choices:
for choice in user_choice.options.all():
choices_count[choice.id] += 1
return render(request, "event_status.html",
{"event": event, "user_choices": user_choices,
"options": options, "choices_count": choices_count,
"form": form})
@buro_required
def survey_status(request, survey_id):
survey = get_object_or_404(Survey, id=survey_id)
answers_query = SurveyAnswer.objects.filter(survey=survey)
post_data = clean_post_for_status(request.POST)
form = SurveyStatusFilterForm(post_data or None, survey=survey)
if form.is_valid():
for question_id, answer_id, value in form.filters():
answer = get_object_or_404(SurveyQuestionAnswer, id=answer_id,
survey_question__id=question_id)
if value == "none":
continue
if value == "yes":
answers_query = answers_query.filter(
answers__id__exact=answer.id)
elif value == "no":
answers_query = answers_query.exclude(
answers__id__exact=answer.id)
user_answers = answers_query.prefetch_related("user").all()
questions = SurveyQuestion.objects.filter(survey=survey).all()
answers_count = {}
for question in questions:
for answer in question.answers.all():
answers_count[answer.id] = 0
for user_answer in user_answers:
for answer in user_answer.answers.all():
answers_count[answer.id] += 1
return render(request, "survey_status.html",
{"survey": survey, "user_answers": user_answers,
"questions": questions, "answers_count": answers_count,
"form": form})
@cof_required
def profile(request):
success = False
if request.method == "POST":
form = UserProfileForm(request.POST, instance=request.user.profile)
if form.is_valid():
form.save()
success = True
else:
form = UserProfileForm(instance=request.user.profile)
return render(request, "profile.html", {"form": form, "success": success})
def registration_set_ro_fields(user_form, profile_form):
user_form.fields['username'].widget.attrs['readonly'] = True
profile_form.fields['login_clipper'].widget.attrs['readonly'] = True
@buro_required
def registration_form2(request, login_clipper=None, username=None):
events = Event.objects.filter(old=False).all()
member = None
if login_clipper:
clipper = get_object_or_404(Clipper, username=login_clipper)
try: # check if the given user is already registered
member = User.objects.get(username=login_clipper)
username = member.username
login_clipper = None
except User.DoesNotExist:
# new user, but prefill
# user
user_form = RegistrationUserForm(initial={
'username': login_clipper,
'email': "%s@clipper.ens.fr" % login_clipper})
if clipper.fullname:
bits = clipper.fullname.split(" ")
user_form.fields['first_name'].initial = bits[0]
if len(bits) > 1:
user_form.fields['last_name'].initial = " ".join(bits[1:])
# profile
profile_form = RegistrationProfileForm(initial={
'login_clipper': login_clipper})
registration_set_ro_fields(user_form, profile_form)
# events
event_formset = EventFormset(events=events, prefix='events')
if username:
member = get_object_or_404(User, username=username)
(profile, _) = CofProfile.objects.get_or_create(user=member)
# already existing, prefill
user_form = RegistrationUserForm(instance=member)
profile_form = RegistrationProfileForm(instance=profile)
registration_set_ro_fields(user_form, profile_form)
# events
current_registrations = []
for event in events:
try:
current_registrations.append(
EventRegistration.objects.get(user=member, event=event))
except EventRegistration.DoesNotExist:
current_registrations.append(None)
event_formset = EventFormset(
events=events, prefix='events',
current_registrations=current_registrations)
elif not login_clipper:
# new user
user_form = RegistrationPassUserForm()
profile_form = RegistrationProfileForm()
event_formset = EventFormset(events=events, prefix='events')
return render(request, "registration_form.html",
{"user_form": user_form, "profile_form": profile_form,
"member": member, "login_clipper": login_clipper,
"event_formset": event_formset})
@buro_required
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
# -----
if 'password1' in request_dict or 'password2' in request_dict:
user_form = RegistrationPassUserForm(request_dict)
else:
user_form = RegistrationUserForm
profile_form = RegistrationProfileForm(request_dict)
events = Event.objects.filter(old=False).all()
event_formset = EventFormset(events=events, data=request_dict,
prefix='events')
if "user_exists" in request_dict and request_dict["user_exists"]:
username = request_dict["username"]
try:
member = User.objects.get(username=username)
user_form = RegistrationUserForm(request_dict, instance=member)
except User.DoesNotExist:
try:
clipper = Clipper.objects.get(username=username)
login_clipper = clipper.username
except Clipper.DoesNotExist:
pass
# -----
# Validation des formulaires
# -----
if user_form.is_valid():
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)
if profile_form.is_valid() and event_formset.is_valid():
profile = profile_form.save()
if profile.is_cof and not was_cof:
send_custom_mail(member, "bienvenue")
for form in event_formset:
if 'status' not in form.cleaned_data:
form.cleaned_data['status'] = 'no'
if form.cleaned_data['status'] == 'no':
try:
current_registration = EventRegistration.objects \
.get(user=member, event=form.event)
current_registration.delete()
except EventRegistration.DoesNotExist:
pass
continue
all_choices = get_event_form_choices(form.event, form)
(current_registration, created_reg) = \
EventRegistration.objects.get_or_create(
user=member, event=form.event)
update_event_form_comments(form.event, form,
current_registration)
current_registration.options = all_choices
current_registration.paid = \
(form.cleaned_data['status'] == 'paid')
current_registration.save()
if form.event.title == "Mega 15" and created_reg:
field = EventCommentField.objects.get(
event=form.event, name="Commentaires")
try:
comments = EventCommentValue.objects.get(
commentfield=field,
registration=current_registration).content
except EventCommentValue.DoesNotExist:
comments = field.default
send_custom_mail(member, "mega",
{"remarques": comments})
success = True
return render(request, "registration_post.html",
{"success": success,
"user_form": user_form,
"profile_form": profile_form,
"member": member,
"login_clipper": login_clipper,
"event_formset": event_formset})
else:
return render(request, "registration.html")
@buro_required
def export_members(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=membres_cof.csv'
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,
user.email, profile.phone, profile.occupation,
profile.departement, profile.type_cotiz]
writer.writerow([six.text_type(bit) for bit in bits])
return response
@buro_required
def csv_export_mega(filename, qs):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=' + filename
writer = unicodecsv.writer(response)
for reg in qs.all():
user = reg.user
profile = user.profile
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.comments if profile.comments else "", comments]
writer.writerow([six.text_type(bit) for bit in bits])
return response
@buro_required
def export_mega_remarksonly(request):
filename = 'remarques_mega_2015.csv'
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=' + filename
writer = unicodecsv.writer(response)
event = Event.objects.get(title="Mega 15")
commentfield = event.commentfields.get(name="Commentaires")
for val in commentfield.values.all():
reg = val.registration
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])
return response
@buro_required
def export_mega_bytype(request, type):
types = {"orga-actif": "Orga élève",
"orga-branleur": "Orga étudiant",
"conscrit-eleve": "Conscrit élève",
"conscrit-etudiant": "Conscrit étudiant"}
if type not in types:
raise Http404
event = Event.objects.get(title="Mega 15")
type_option = event.options.get(name="Type")
participant_type = type_option.choices.get(value=types[type]).id
qs = EventRegistration.objects.filter(event=event).filter(
options__id__exact=participant_type)
return csv_export_mega(type + '_mega_2015.csv', qs)
@buro_required
def export_mega_orgas(request):
event = Event.objects.get(title="Mega 15")
type_option = event.options.get(name="Type")
participant_type_a = type_option.choices.get(value="Conscrit étudiant").id
participant_type_b = type_option.choices.get(value="Conscrit élève").id
qs = EventRegistration.objects.filter(event=event).exclude(
options__id__in=(participant_type_a, participant_type_b))
return csv_export_mega('orgas_mega_15.csv', qs)
@buro_required
def export_mega_participants(request):
event = Event.objects.get(title="Mega 15")
type_option = event.options.get(name="Type")
participant_type_a = type_option.choices.get(value="Conscrit étudiant").id
participant_type_b = type_option.choices.get(value="Conscrit élève").id
qs = EventRegistration.objects.filter(event=event).filter(
options__id__in=(participant_type_a, participant_type_b))
return csv_export_mega('participants_mega_15.csv', qs)
@buro_required
def export_mega(request):
event = Event.objects.filter(title="Mega 15")
qs = EventRegistration.objects.filter(event=event) \
.order_by("user__username")
return csv_export_mega('all_mega_2015.csv', qs)
@buro_required
def utile_cof(request):
return render(request, "utile_cof.html", {})
@buro_required
def utile_bda(request):
tirages = Tirage.objects.all()
return render(request, "utile_bda.html", {'tirages': tirages})
@buro_required
def liste_bdadiff(request):
titre = "BdA diffusion"
personnes = CofProfile.objects.filter(mailing_bda=True, is_cof=True).all()
return render(request, "liste_mails.html",
{"titre": titre, "personnes": personnes})
@buro_required
def liste_bdarevente(request):
titre = "BdA revente"
personnes = CofProfile.objects.filter(mailing_bda_revente=True,
is_cof=True).all()
return render(request, "liste_mails.html", {"titre": titre,
"personnes": personnes})
@buro_required
def liste_diffcof(request):
titre = "Diffusion COF"
personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all()
return render(request, "liste_mails.html", {"titre": titre,
"personnes": personnes})
@cof_required
def calendar(request):
try:
instance = CalendarSubscription.objects.get(user=request.user)
except CalendarSubscription.DoesNotExist:
instance = None
if request.method == 'POST':
form = CalendarForm(request.POST, instance=instance)
if form.is_valid():
subscription = form.save(commit=False)
if instance is None:
subscription.user = request.user
subscription.token = uuid.uuid4()
subscription.save()
form.save_m2m()
return render(request, "calendar_subscription.html",
{'form': form,
'success': True,
'token': str(subscription.token)})
else:
return render(request, "calendar_subscription.html",
{'form': form, 'error': "Formulaire incorrect"})
else:
return render(request, "calendar_subscription.html",
{'form': CalendarForm(instance=instance),
'token': instance.token if instance else None})
def calendar_ics(request, token):
subscription = get_object_or_404(CalendarSubscription, token=token)
shows = subscription.other_shows.all()
if subscription.subscribe_to_my_shows:
shows |= Spectacle.objects.filter(
attribues__participant__user=subscription.user,
tirage__active=True)
shows = shows.distinct()
vcal = Calendar()
for show in shows:
vevent = Vevent()
vevent.add('dtstart', show.date)
vevent.add('dtend', show.date + timedelta(seconds=7200))
vevent.add('summary', show.title)
vevent.add('location', show.location.name)
vcal.add_component(vevent)
if subscription.subscribe_to_events:
for event in Event.objects.filter(old=False).all():
vevent = Vevent()
vevent.add('dtstart', event.start_date)
vevent.add('dtend', event.end_date)
vevent.add('summary', event.title)
vevent.add('location', event.location)
vevent.add('description', event.description)
vcal.add_component(vevent)
response = HttpResponse(content=vcal.to_ical())
response['Content-Type'] = "text/calendar"
return response