mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2024-11-27 04:13:01 +00:00
4317947501
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
931 lines
40 KiB
Python
931 lines
40 KiB
Python
# Copyright (C) 2020 by Animath
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
from tempfile import mkdtemp
|
|
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
|
|
from django.contrib.auth.models import User
|
|
from django.contrib.sites.models import Site
|
|
from django.core.exceptions import PermissionDenied, ValidationError
|
|
from django.db import transaction
|
|
from django.db.models import Q
|
|
from django.http import FileResponse, Http404
|
|
from django.shortcuts import redirect, resolve_url
|
|
from django.template.loader import render_to_string
|
|
from django.urls import reverse_lazy
|
|
from django.utils import translation
|
|
from django.utils.crypto import get_random_string
|
|
from django.utils.http import urlsafe_base64_decode
|
|
from django.utils.text import format_lazy
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View
|
|
from django_tables2 import SingleTableView
|
|
from magic import Magic
|
|
from participation.models import Passage, Solution, Tournament, WrittenReview
|
|
from tfjm.tokens import email_validation_token
|
|
from tfjm.views import UserMixin, UserRegistrationMixin, VolunteerMixin
|
|
|
|
from .forms import AddOrganizerForm, CoachRegistrationForm, HealthSheetForm, \
|
|
ParentalAuthorizationFinalForm, ParentalAuthorizationForm, PaymentAdminForm, PaymentForm, \
|
|
PhotoAuthorizationFinalForm, PhotoAuthorizationForm, SignupForm, StudentRegistrationForm, UserForm, \
|
|
VaccineSheetForm, VolunteerRegistrationForm
|
|
from .models import ParticipantRegistration, Payment, Registration, StudentRegistration
|
|
from .tables import RegistrationTable
|
|
|
|
|
|
class SignupView(CreateView):
|
|
"""
|
|
Signup, as a participant or a coach.
|
|
"""
|
|
model = User
|
|
form_class = SignupForm
|
|
template_name = "registration/signup.html"
|
|
extra_context = dict(title=_("Sign up"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data()
|
|
|
|
context["student_registration_form"] = StudentRegistrationForm(self.request.POST or None)
|
|
context["coach_registration_form"] = CoachRegistrationForm(self.request.POST or None)
|
|
|
|
del context["student_registration_form"].fields["team"]
|
|
del context["student_registration_form"].fields["email_confirmed"]
|
|
del context["coach_registration_form"].fields["team"]
|
|
del context["coach_registration_form"].fields["email_confirmed"]
|
|
|
|
return context
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
role = form.cleaned_data["role"]
|
|
if role == "participant":
|
|
registration_form = StudentRegistrationForm(self.request.POST)
|
|
else:
|
|
registration_form = CoachRegistrationForm(self.request.POST)
|
|
del registration_form.fields["team"]
|
|
del registration_form.fields["email_confirmed"]
|
|
|
|
if not registration_form.is_valid():
|
|
return self.form_invalid(form)
|
|
|
|
ret = super().form_valid(form)
|
|
registration = registration_form.instance
|
|
registration.user = form.instance
|
|
registration.save()
|
|
registration.send_email_validation_link()
|
|
|
|
return ret
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:email_validation_sent")
|
|
|
|
|
|
class AddOrganizerView(VolunteerMixin, CreateView):
|
|
model = User
|
|
form_class = AddOrganizerForm
|
|
template_name = "registration/add_organizer.html"
|
|
extra_context = dict(title=_("Add organizer"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data()
|
|
|
|
context["volunteer_registration_form"] = VolunteerRegistrationForm(self.request.POST or None)
|
|
del context["volunteer_registration_form"].fields["email_confirmed"]
|
|
if not self.request.user.registration.is_admin:
|
|
del context["volunteer_registration_form"].fields["admin"]
|
|
|
|
return context
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
registration_form = VolunteerRegistrationForm(self.request.POST)
|
|
del registration_form.fields["email_confirmed"]
|
|
if not self.request.user.registration.is_admin:
|
|
del registration_form.fields["admin"]
|
|
|
|
if not registration_form.is_valid():
|
|
return self.form_invalid(form)
|
|
|
|
ret = super().form_valid(form)
|
|
registration = registration_form.instance
|
|
registration.user = form.instance
|
|
registration.save()
|
|
registration.send_email_validation_link()
|
|
|
|
password = get_random_string(16)
|
|
form.instance.set_password(password)
|
|
form.instance.save()
|
|
|
|
subject = f"[{settings.APP_NAME}] " + str(_("New organizer account"))
|
|
site = Site.objects.first()
|
|
message = render_to_string('registration/mails/add_organizer.txt', dict(user=registration.user,
|
|
inviter=self.request.user,
|
|
password=password,
|
|
domain=site.domain))
|
|
html = render_to_string('registration/mails/add_organizer.html', dict(user=registration.user,
|
|
inviter=self.request.user,
|
|
password=password,
|
|
domain=site.domain))
|
|
registration.user.email_user(subject, message, html_message=html)
|
|
|
|
if registration.is_admin:
|
|
registration.user.is_superuser = True
|
|
registration.user.save()
|
|
|
|
return ret
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:email_validation_sent")
|
|
|
|
|
|
class UserValidateView(TemplateView):
|
|
"""
|
|
A view to validate the email address.
|
|
"""
|
|
title = _("Email validation")
|
|
template_name = 'registration/email_validation_complete.html'
|
|
extra_context = dict(title=_("Validate email"))
|
|
|
|
def get(self, *args, **kwargs):
|
|
"""
|
|
With a given token and user id (in params), validate the email address.
|
|
"""
|
|
assert 'uidb64' in kwargs and 'token' in kwargs
|
|
|
|
self.validlink = False
|
|
user = self.get_user(kwargs['uidb64'])
|
|
token = kwargs['token']
|
|
|
|
# Validate the token
|
|
if user is not None and email_validation_token.check_token(user, token):
|
|
self.validlink = True
|
|
user.registration.email_confirmed = True
|
|
user.registration.save()
|
|
return self.render_to_response(self.get_context_data(), status=200 if self.validlink else 400)
|
|
|
|
def get_user(self, uidb64):
|
|
"""
|
|
Get user from the base64-encoded string.
|
|
"""
|
|
try:
|
|
# urlsafe_base64_decode() decodes to bytestring
|
|
uid = urlsafe_base64_decode(uidb64).decode()
|
|
user = User.objects.get(pk=uid)
|
|
except (TypeError, ValueError, OverflowError, User.DoesNotExist, ValidationError):
|
|
user = None
|
|
return user
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['user_object'] = self.get_user(self.kwargs["uidb64"])
|
|
context['login_url'] = resolve_url(settings.LOGIN_URL)
|
|
if self.validlink:
|
|
context['validlink'] = True
|
|
else:
|
|
context.update({
|
|
'title': _('Email validation unsuccessful'),
|
|
'validlink': False,
|
|
})
|
|
return context
|
|
|
|
|
|
class UserValidationEmailSentView(TemplateView):
|
|
"""
|
|
Display the information that the validation link has been sent.
|
|
"""
|
|
template_name = 'registration/email_validation_email_sent.html'
|
|
extra_context = dict(title=_('Email validation email sent'))
|
|
|
|
|
|
class UserResendValidationEmailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Rensend the email validation link.
|
|
"""
|
|
model = User
|
|
extra_context = dict(title=_("Resend email validation link"))
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
user = self.get_object()
|
|
user.registration.send_email_validation_link()
|
|
return redirect('registration:email_validation_sent')
|
|
|
|
|
|
class MyAccountDetailView(LoginRequiredMixin, RedirectView):
|
|
"""
|
|
Redirect to our own profile detail page.
|
|
"""
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
return reverse_lazy("registration:user_detail", args=(self.request.user.pk,))
|
|
|
|
|
|
class UserDetailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Display the detail about a user.
|
|
"""
|
|
|
|
model = User
|
|
context_object_name = "user_object"
|
|
template_name = "registration/user_detail.html"
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
me = request.user
|
|
if not me.is_authenticated:
|
|
return self.handle_no_permission()
|
|
user = self.get_object()
|
|
if user == me or me.registration.is_admin or me.registration.is_volunteer \
|
|
and user.registration.participates and user.registration.team \
|
|
and (user.registration.team.participation.tournament in me.registration.organized_tournaments.all()
|
|
or user.registration.team.participation.final
|
|
and Tournament.final_tournament() in me.registration.organized_tournaments.all()) \
|
|
or user.registration.is_volunteer and me.registration.is_volunteer \
|
|
and me.registration.interesting_tournaments.intersection(user.registration.interesting_tournaments):
|
|
return super().dispatch(request, *args, **kwargs)
|
|
raise PermissionDenied
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context["title"] = _("Detail of user {user}").format(user=str(self.object.registration))
|
|
return context
|
|
|
|
|
|
class UserListView(VolunteerMixin, SingleTableView):
|
|
"""
|
|
Display the list of all registered users.
|
|
"""
|
|
model = Registration
|
|
table_class = RegistrationTable
|
|
template_name = "registration/user_list.html"
|
|
|
|
|
|
class UserUpdateView(UserMixin, UpdateView):
|
|
"""
|
|
Update the detail about a user and its registration.
|
|
"""
|
|
model = User
|
|
context_object_name = "user_object"
|
|
form_class = UserForm
|
|
template_name = "registration/update_user.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
user = self.get_object()
|
|
context["title"] = _("Update user {user}").format(user=str(self.object.registration))
|
|
context["registration_form"] = user.registration.form_class(data=self.request.POST or None,
|
|
instance=self.object.registration)
|
|
if not self.request.user.registration.is_admin:
|
|
if "team" in context["registration_form"].fields:
|
|
del context["registration_form"].fields["team"]
|
|
if "admin" in context["registration_form"].fields:
|
|
del context["registration_form"].fields["admin"]
|
|
del context["registration_form"].fields["email_confirmed"]
|
|
return context
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
user = form.instance
|
|
registration_form = user.registration.form_class(data=self.request.POST or None,
|
|
instance=self.object.registration)
|
|
if not self.request.user.registration.is_admin:
|
|
if "team" in registration_form.fields:
|
|
del registration_form.fields["team"]
|
|
if "admin" in registration_form.fields:
|
|
del registration_form.fields["admin"]
|
|
del registration_form.fields["email_confirmed"]
|
|
|
|
if not registration_form.is_valid():
|
|
return self.form_invalid(form)
|
|
|
|
registration_form.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.object.pk,))
|
|
|
|
|
|
class UserUploadPhotoAuthorizationView(UserRegistrationMixin, UpdateView):
|
|
"""
|
|
A participant can send its photo authorization.
|
|
"""
|
|
model = ParticipantRegistration
|
|
template_name = "registration/upload_photo_authorization.html"
|
|
extra_context = dict(title=_("Upload photo authorization"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
if self.object.team:
|
|
tournament = self.object.team.participation.tournament \
|
|
if 'final' not in self.request.path else Tournament.final_tournament()
|
|
context["tournament"] = tournament
|
|
return context
|
|
|
|
def get_form_class(self):
|
|
return PhotoAuthorizationForm if 'final' not in self.request.path else PhotoAuthorizationFinalForm
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
old_instance: ParticipantRegistration = ParticipantRegistration.objects.get(pk=self.object.pk)
|
|
old_field = old_instance.photo_authorization \
|
|
if 'final' not in self.request.path else old_instance.photo_authorization_final
|
|
if old_field:
|
|
old_field.delete()
|
|
old_instance.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.object.user.pk,))
|
|
|
|
|
|
class UserUploadHealthSheetView(UserRegistrationMixin, UpdateView):
|
|
"""
|
|
A participant can send its health sheet.
|
|
"""
|
|
model = StudentRegistration
|
|
form_class = HealthSheetForm
|
|
template_name = "registration/upload_health_sheet.html"
|
|
extra_context = dict(title=_("Upload health sheet"))
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
old_instance = StudentRegistration.objects.get(pk=self.object.pk)
|
|
if old_instance.health_sheet:
|
|
old_instance.health_sheet.delete()
|
|
old_instance.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.object.user.pk,))
|
|
|
|
|
|
class UserUploadVaccineSheetView(UserRegistrationMixin, UpdateView):
|
|
"""
|
|
A participant can send its vaccine sheet.
|
|
"""
|
|
model = StudentRegistration
|
|
form_class = VaccineSheetForm
|
|
template_name = "registration/upload_vaccine_sheet.html"
|
|
extra_context = dict(title=_("Upload vaccine sheet"))
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
old_instance = StudentRegistration.objects.get(pk=self.object.pk)
|
|
if old_instance.vaccine_sheet:
|
|
old_instance.vaccine_sheet.delete()
|
|
old_instance.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.object.user.pk,))
|
|
|
|
|
|
class UserUploadParentalAuthorizationView(UserRegistrationMixin, UpdateView):
|
|
"""
|
|
A participant can send its parental authorization.
|
|
"""
|
|
model = StudentRegistration
|
|
template_name = "registration/upload_parental_authorization.html"
|
|
extra_context = dict(title=_("Upload parental authorization"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
if self.object.team:
|
|
tournament = self.object.team.participation.tournament \
|
|
if 'final' not in self.request.path else Tournament.final_tournament()
|
|
context["tournament"] = tournament
|
|
return context
|
|
|
|
def get_form_class(self):
|
|
return ParentalAuthorizationForm if 'final' not in self.request.path else ParentalAuthorizationFinalForm
|
|
|
|
@transaction.atomic
|
|
def form_valid(self, form):
|
|
old_instance: StudentRegistration = StudentRegistration.objects.get(pk=self.object.pk)
|
|
old_field = old_instance.parental_authorization \
|
|
if 'final' not in self.request.path else old_instance.parental_authorization_final
|
|
if old_field:
|
|
old_field.delete()
|
|
old_instance.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("registration:user_detail", args=(self.object.user.pk,))
|
|
|
|
|
|
class AuthorizationTemplateView(TemplateView):
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
translation.activate("fr")
|
|
|
|
if "registration_id" in self.request.GET:
|
|
registration = Registration.objects.get(pk=self.request.GET.get("registration_id"))
|
|
# Don't get unwanted information
|
|
if registration.user == self.request.user \
|
|
or self.request.user.is_authenticated and self.request.user.registration.is_admin:
|
|
context["registration"] = registration
|
|
if "tournament_id" in self.request.GET and self.request.GET.get("tournament_id").isnumeric():
|
|
if not Tournament.objects.filter(pk=self.request.GET.get("tournament_id")).exists():
|
|
raise PermissionDenied("Ce tournoi n'existe pas.")
|
|
context["tournament"] = Tournament.objects.get(pk=self.request.GET.get("tournament_id"))
|
|
elif "tournament_name" in self.request.GET:
|
|
if not Tournament.objects.filter(name__iexact=self.request.GET.get("tournament_name")).exists():
|
|
raise PermissionDenied("Ce tournoi n'existe pas.")
|
|
context["tournament"] = Tournament.objects.get(name__iexact=self.request.GET.get("tournament_name"))
|
|
elif settings.SINGLE_TOURNAMENT:
|
|
# One single tournament (for ETEAM)
|
|
context["tournament"] = Tournament.objects.first()
|
|
else:
|
|
raise PermissionDenied("Merci d'indiquer un tournoi.")
|
|
|
|
return context
|
|
|
|
def render_to_response(self, context, **response_kwargs):
|
|
translation.activate(settings.PREFERRED_LANGUAGE_CODE)
|
|
|
|
template_name = self.get_template_names()[0]
|
|
tex = render_to_string(template_name, context=context, request=self.request)
|
|
temp_dir = mkdtemp()
|
|
with open(os.path.join(temp_dir, "texput.tex"), "w") as f:
|
|
f.write(tex)
|
|
process = subprocess.Popen(["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}",
|
|
os.path.join(temp_dir, "texput.tex"), ])
|
|
process.wait()
|
|
return FileResponse(open(os.path.join(temp_dir, "texput.pdf"), "rb"),
|
|
content_type="application/pdf",
|
|
filename=template_name.split("/")[-1][:-3] + "pdf")
|
|
|
|
|
|
class AdultPhotoAuthorizationTemplateView(AuthorizationTemplateView):
|
|
def get_template_names(self):
|
|
if settings.TFJM_APP == "TFJM":
|
|
return ["registration/tex/Autorisation_droit_image_majeur.tex"]
|
|
elif settings.TFJM_APP == "ETEAM":
|
|
return ["registration/tex/photo_authorization_eteam_adult.tex"]
|
|
|
|
|
|
class ChildPhotoAuthorizationTemplateView(AuthorizationTemplateView):
|
|
def get_template_names(self):
|
|
if settings.TFJM_APP == "TFJM":
|
|
return ["registration/tex/Autorisation_droit_image_mineur.tex"]
|
|
elif settings.TFJM_APP == "ETEAM":
|
|
return ["registration/tex/photo_authorization_eteam_child.tex"]
|
|
|
|
|
|
class ParentalAuthorizationTemplateView(AuthorizationTemplateView):
|
|
template_name = "registration/tex/Autorisation_parentale.tex"
|
|
|
|
def get_template_names(self):
|
|
if settings.TFJM_APP == "TFJM":
|
|
return ["registration/tex/Autorisation_parentale.tex"]
|
|
elif settings.TFJM_APP == "ETEAM":
|
|
return ["registration/tex/parental_authorization_eteam.tex"]
|
|
|
|
|
|
class InstructionsTemplateView(AuthorizationTemplateView):
|
|
template_name = "registration/tex/Instructions.tex"
|
|
|
|
|
|
class PaymentUpdateView(LoginRequiredMixin, UpdateView):
|
|
model = Payment
|
|
form_class = PaymentAdminForm
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
user = self.request.user
|
|
object = self.get_object()
|
|
if not user.is_authenticated or \
|
|
not user.registration.is_admin \
|
|
and (user.registration.is_volunteer and user.registration not in object.tournament.organizers.all()
|
|
or user.registration.is_student and user.registration not in object.registrations.all()
|
|
or user.registration.is_coach and user.registration.team != object.team):
|
|
return self.handle_no_permission()
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data()
|
|
context['title'] = _("Update payment")
|
|
# Grouping is only possible if there isn't any validated payment in the team
|
|
context['can_group'] = all(p.valid is False for reg in self.object.team.students.all()
|
|
for p in reg.payments.filter(final=self.object.final).all())
|
|
context['bank_transfer_form'] = PaymentForm(payment_type='bank_transfer',
|
|
data=self.request.POST or None,
|
|
instance=self.object)
|
|
|
|
if not self.object.grouped:
|
|
context['scholarship_form'] = PaymentForm(payment_type='scholarship',
|
|
data=self.request.POST or None,
|
|
instance=self.object)
|
|
|
|
context['other_form'] = PaymentForm(payment_type='other',
|
|
data=self.request.POST or None,
|
|
instance=self.object)
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
old_instance = Payment.objects.get(pk=self.object.pk)
|
|
if self.request.user.registration.participates:
|
|
if old_instance.valid is not False:
|
|
raise PermissionDenied(_("This payment is already valid or pending validation."))
|
|
if old_instance.valid is False:
|
|
form.instance.valid = None
|
|
if old_instance.receipt:
|
|
old_instance.receipt.delete()
|
|
old_instance.save()
|
|
return super().form_valid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("participation:team_detail", args=(self.object.registrations.first().team.pk,))
|
|
|
|
|
|
class PaymentUpdateGroupView(LoginRequiredMixin, DetailView):
|
|
model = Payment
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
payment = self.get_object()
|
|
|
|
if not self.request.user.is_authenticated or \
|
|
not self.request.user.registration.is_admin \
|
|
and (self.request.user.registration not in self.get_object().registrations.all()
|
|
or payment.valid is not False):
|
|
return self.handle_no_permission()
|
|
|
|
if any(p.valid is not False for reg in payment.team.students.all()
|
|
for p in reg.payments.filter(final=payment.final).all()):
|
|
raise PermissionDenied(_("Since one payment is already validated, or pending validation, "
|
|
"grouping is not possible."))
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
payment = self.get_object()
|
|
|
|
if payment.valid is not False:
|
|
raise PermissionDenied(_("This payment is already valid or pending validation."))
|
|
|
|
if payment.grouped:
|
|
registrations = list(payment.registrations.all())
|
|
first_reg = registrations[0]
|
|
payment.registrations.set([first_reg])
|
|
payment.grouped = False
|
|
tournament = first_reg.team.participation.tournament if not payment.final else Tournament.final_tournament()
|
|
payment.amount = tournament.price
|
|
payment.checkout_intent_id = None
|
|
payment.save()
|
|
for registration in registrations[1:]:
|
|
p = Payment.objects.create(type=payment.type,
|
|
grouped=False,
|
|
final=payment.final,
|
|
amount=tournament.price,
|
|
receipt=payment.receipt,
|
|
additional_information=payment.additional_information)
|
|
p.registrations.set([registration])
|
|
p.save()
|
|
else:
|
|
reg = payment.registrations.get()
|
|
tournament = reg.team.participation.tournament if not payment.final else Tournament.final_tournament()
|
|
for student in reg.team.students.all():
|
|
if student != reg:
|
|
Payment.objects.filter(registrations=student, final=payment.final).delete()
|
|
payment.registrations.add(student)
|
|
payment.amount = tournament.price * reg.team.students.count()
|
|
payment.grouped = True
|
|
payment.checkout_intent_id = None
|
|
payment.save()
|
|
|
|
return redirect(reverse_lazy("registration:update_payment", args=(payment.pk,)))
|
|
|
|
|
|
class PaymentRedirectHelloAssoView(AccessMixin, DetailView):
|
|
model = Payment
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
payment = self.get_object()
|
|
|
|
# An external user has the link for the payment
|
|
token = request.GET.get('token', "")
|
|
if token and token == payment.token:
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
if not request.user.is_authenticated:
|
|
return self.handle_no_permission()
|
|
|
|
if not request.user.registration.is_admin:
|
|
if request.user.registration.is_volunteer \
|
|
and payment.tournament not in request.user.registration.organized_tournaments.all():
|
|
return self.handle_no_permission()
|
|
|
|
if request.user.registration.is_student \
|
|
and request.user.registration not in payment.registrations.all():
|
|
return self.handle_no_permission()
|
|
|
|
if request.user.registration.is_coach \
|
|
and request.user.registration.team != payment.team:
|
|
return self.handle_no_permission()
|
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
payment = self.get_object()
|
|
if payment.valid is not False:
|
|
raise PermissionDenied(_("The payment is already valid or pending validation."))
|
|
|
|
checkout_intent = payment.create_checkout_intent()
|
|
return redirect(checkout_intent["redirectUrl"])
|
|
|
|
|
|
class PaymentHelloAssoReturnView(DetailView):
|
|
model = Payment
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
checkout_id = request.GET.get("checkoutIntentId")
|
|
payment = self.get_object()
|
|
payment_qs = Payment.objects.exclude(valid=True).filter(checkout_intent_id=checkout_id).filter(pk=payment.pk)
|
|
if not payment_qs.exists():
|
|
messages.error(request, _("The payment is not found or is already validated."), "danger")
|
|
return redirect("index")
|
|
|
|
team = payment.team
|
|
tournament = payment.tournament
|
|
right_to_see = not request.user.is_anonymous \
|
|
and (request.user.registration.is_admin
|
|
or request.user.registration in payment.registrations.all()
|
|
or (request.user.registration.is_volunteer
|
|
and tournament in request.user.registration.organized_tournaments.all())
|
|
or (request.user.registration.is_coach and request.user.registration.team == team))
|
|
|
|
if right_to_see:
|
|
error_response = redirect("registration:update_payment", pk=payment.pk)
|
|
else:
|
|
error_response = redirect("index")
|
|
|
|
return_type = request.GET.get("type")
|
|
if return_type == "error":
|
|
messages.error(request, format_lazy(_("An error occurred during the payment: {error}"),
|
|
error=request.GET.get("error")), "danger")
|
|
return error_response
|
|
elif return_type == "return":
|
|
code = request.GET.get("code")
|
|
if code == "refused":
|
|
messages.error(request, _("The payment has been refused."), "danger")
|
|
return error_response
|
|
elif code != "succeeded":
|
|
messages.error(request, format_lazy(_("The return code is unknown: {code}"), code=code), "danger")
|
|
return error_response
|
|
else:
|
|
messages.error(request, format_lazy(_("The return type is unknown: {type}"), type=return_type), "danger")
|
|
return error_response
|
|
|
|
checkout_intent = payment.get_checkout_intent()
|
|
if 'order' in checkout_intent:
|
|
payment.type = "helloasso"
|
|
payment.valid = True
|
|
payment.additional_information = json.dumps(checkout_intent['order'])
|
|
payment.save()
|
|
messages.success(request, _("The payment has been successfully validated! "
|
|
"Your registration is now complete."))
|
|
payment.send_helloasso_payment_confirmation_mail()
|
|
else:
|
|
payment.type = "helloasso"
|
|
payment.valid = None
|
|
payment.save()
|
|
messages.success(request, _("Your payment is done! "
|
|
"The validation of your payment may takes a few minutes, "
|
|
"and will be automatically done. "
|
|
"If it is not the case, please contact us."))
|
|
|
|
if right_to_see:
|
|
return redirect("participation:team_detail", pk=team.pk)
|
|
else:
|
|
return redirect("index")
|
|
|
|
|
|
class PhotoAuthorizationView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent photo authorization.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/authorization/photo/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
student = ParticipantRegistration.objects.get(Q(photo_authorization__endswith=filename)
|
|
| Q(photo_authorization_final__endswith=filename))
|
|
user = request.user
|
|
if not (student.user == user or user.registration.is_admin or user.registration.is_volunteer and student.team
|
|
and student.team.participation.tournament in user.registration.organized_tournaments.all()):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = _("Photo authorization of {student}.{ext}").format(student=str(student), ext=ext)
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class HealthSheetView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent health sheet.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/authorization/health/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
student = StudentRegistration.objects.get(health_sheet__endswith=filename)
|
|
user = request.user
|
|
if not (student.user == user or user.registration.is_admin or user.registration.is_volunteer and student.team
|
|
and student.team.participation.tournament in user.registration.organized_tournaments.all()):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = _("Health sheet of {student}.{ext}").format(student=str(student), ext=ext)
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class VaccineSheetView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent health sheet.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/authorization/vaccine/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
student = StudentRegistration.objects.get(vaccine_sheet__endswith=filename)
|
|
user = request.user
|
|
if not (student.user == user or user.registration.is_admin or user.registration.is_volunteer and student.team
|
|
and student.team.participation.tournament in user.registration.organized_tournaments.all()):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = _("Vaccine sheet of {student}.{ext}").format(student=str(student), ext=ext)
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class ParentalAuthorizationView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent parental authorization.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/authorization/parental/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
student = StudentRegistration.objects.get(Q(parental_authorization__endswith=filename)
|
|
| Q(parental_authorization_final__endswith=filename))
|
|
user = request.user
|
|
if not (student.user == user or user.registration.is_admin or user.registration.is_volunteer and student.team
|
|
and student.team.participation.tournament in user.registration.organized_tournaments.all()):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = _("Parental authorization of {student}.{ext}").format(student=str(student), ext=ext)
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class ReceiptView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent payment receipt or scholarship notification.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/authorization/receipt/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
payment = Payment.objects.get(receipt__endswith=filename)
|
|
user = request.user
|
|
if not (user.registration in payment.registrations.all() or user.registration.is_admin):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
registrations = ", ".join(str(registration) for registration in payment.registrations.all())
|
|
true_file_name = _("Payment receipt of {registrations}.{ext}").format(registrations=registrations, ext=ext)
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class SolutionView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent solution.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/solutions/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
solution = Solution.objects.get(file__endswith=filename)
|
|
user = request.user
|
|
if user.registration.participates and user.registration.team.participation:
|
|
passage_participant_qs = Passage.objects.filter(Q(reporter=user.registration.team.participation)
|
|
| Q(opponent=user.registration.team.participation)
|
|
| Q(reviewer=user.registration.team.participation)
|
|
| Q(observer=user.registration.team.participation),
|
|
reporter=solution.participation,
|
|
solution_number=solution.problem)
|
|
else:
|
|
passage_participant_qs = Passage.objects.none()
|
|
if not (user.registration.is_admin
|
|
or (user.registration.is_volunteer
|
|
and user.registration in solution.tournament.organizers.all())
|
|
or (user.registration.is_volunteer
|
|
and user.registration.pools_presided.filter(tournament=solution.tournament).exists())
|
|
or user.registration.is_volunteer
|
|
and Passage.objects.filter(Q(pool__juries=user.registration)
|
|
| Q(pool__tournament__in=user.registration.organized_tournaments.all()),
|
|
reporter=solution.participation,
|
|
solution_number=solution.problem).exists()
|
|
or user.registration.participates and user.registration.team
|
|
and (solution.participation.team == user.registration.team or
|
|
any(passage.pool.round == 1
|
|
or (passage.pool.round == 2 and passage.pool.tournament.solutions_available_second_phase)
|
|
or (passage.pool.round == 3 and passage.pool.tournament.solutions_available_third_phase)
|
|
for passage in passage_participant_qs.all()))):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = str(solution) + f".{ext}"
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class WrittenReviewView(LoginRequiredMixin, View):
|
|
"""
|
|
Display the sent written reviews.
|
|
"""
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
filename = kwargs["filename"]
|
|
path = f"media/reviews/{filename}"
|
|
if not os.path.exists(path):
|
|
raise Http404
|
|
review = WrittenReview.objects.get(file__endswith=filename)
|
|
user = request.user
|
|
if not (user.registration.is_admin or user.registration.is_volunteer
|
|
and (user.registration in review.passage.pool.juries.all()
|
|
or user.registration in review.passage.pool.tournament.organizers.all()
|
|
or user.registration.pools_presided.filter(tournament=review.passage.pool.tournament).exists())
|
|
or user.registration.participates and user.registration.team == review.participation.team):
|
|
raise PermissionDenied
|
|
# Guess mime type of the file
|
|
mime = Magic(mime=True)
|
|
mime_type = mime.from_file(path)
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
# Replace file name
|
|
true_file_name = str(review) + f".{ext}"
|
|
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
|
|
|
|
|
class UserImpersonateView(LoginRequiredMixin, RedirectView):
|
|
"""
|
|
An administrator can log in through this page as someone else, and act as this other person.
|
|
"""
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if self.request.user.registration.is_admin:
|
|
if not User.objects.filter(pk=kwargs["pk"]).exists():
|
|
raise Http404
|
|
session = request.session
|
|
session["admin"] = request.user.pk
|
|
session["_fake_user_id"] = kwargs["pk"]
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
return reverse_lazy("registration:user_detail", args=(kwargs["pk"],))
|
|
|
|
|
|
class ResetAdminView(LoginRequiredMixin, View):
|
|
"""
|
|
Return to admin view, clear the session field that let an administrator to log in as someone else.
|
|
"""
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
user = request.user
|
|
if not user.is_authenticated:
|
|
return self.handle_no_permission()
|
|
if "_fake_user_id" in request.session:
|
|
del request.session["_fake_user_id"]
|
|
return redirect(request.GET.get("path", reverse_lazy("index")))
|