2020-09-27 16:40:45 +00:00
|
|
|
from io import BytesIO
|
2020-10-15 18:39:34 +00:00
|
|
|
import os
|
2020-09-27 16:40:45 +00:00
|
|
|
from zipfile import ZipFile
|
|
|
|
|
2020-10-09 11:58:42 +00:00
|
|
|
from corres2math.lists import get_sympa_client
|
2020-10-20 11:14:02 +00:00
|
|
|
from corres2math.views import AdminMixin
|
2020-09-22 18:41:42 +00:00
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
2020-09-24 08:21:50 +00:00
|
|
|
from django.core.exceptions import PermissionDenied
|
2020-10-15 18:39:34 +00:00
|
|
|
from django.core.mail import send_mail
|
2020-09-23 21:20:44 +00:00
|
|
|
from django.db import transaction
|
2020-10-09 11:58:42 +00:00
|
|
|
from django.http import HttpResponse
|
2020-10-11 15:40:18 +00:00
|
|
|
from django.template.loader import render_to_string
|
2020-09-23 21:20:44 +00:00
|
|
|
from django.urls import reverse_lazy
|
2020-09-22 18:41:42 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2020-09-24 10:06:33 +00:00
|
|
|
from django.views.generic import CreateView, DetailView, FormView, RedirectView, UpdateView
|
2020-10-11 16:44:42 +00:00
|
|
|
from django.views.generic.edit import FormMixin, ProcessFormView
|
2020-10-20 11:06:51 +00:00
|
|
|
from django_tables2 import SingleTableView
|
2020-09-27 16:40:45 +00:00
|
|
|
from magic import Magic
|
2020-10-11 15:40:18 +00:00
|
|
|
from registration.models import AdminRegistration
|
2020-09-21 13:41:55 +00:00
|
|
|
|
2020-10-20 11:14:02 +00:00
|
|
|
from .forms import JoinTeamForm, ParticipationForm, PhaseForm, RequestValidationForm, TeamForm, UploadVideoForm,\
|
2020-10-11 16:44:42 +00:00
|
|
|
ValidateParticipationForm
|
2020-10-20 11:06:51 +00:00
|
|
|
from .models import Participation, Phase, Team, Video
|
|
|
|
from .tables import CalendarTable
|
2020-09-22 18:41:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CreateTeamView(LoginRequiredMixin, CreateView):
|
|
|
|
model = Team
|
|
|
|
form_class = TeamForm
|
|
|
|
extra_context = dict(title=_("Create team"))
|
|
|
|
template_name = "participation/create_team.html"
|
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
2020-09-23 21:20:44 +00:00
|
|
|
registration = user.registration
|
|
|
|
if not registration.participates:
|
2020-09-27 14:35:31 +00:00
|
|
|
raise PermissionDenied(_("You don't participate, so you can't create a team."))
|
2020-09-23 21:20:44 +00:00
|
|
|
elif registration.team:
|
2020-09-27 14:35:31 +00:00
|
|
|
raise PermissionDenied(_("You are already in a team."))
|
|
|
|
return super().dispatch(request, *args, **kwargs)
|
2020-09-23 21:20:44 +00:00
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
@transaction.atomic
|
|
|
|
def form_valid(self, form):
|
2020-09-23 21:20:44 +00:00
|
|
|
ret = super().form_valid(form)
|
2020-09-27 14:35:31 +00:00
|
|
|
user = self.request.user
|
|
|
|
registration = user.registration
|
2020-09-23 21:20:44 +00:00
|
|
|
registration.team = form.instance
|
|
|
|
registration.save()
|
2020-10-09 11:49:09 +00:00
|
|
|
get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
|
|
|
|
f"{user.first_name} {user.last_name}")
|
2020-09-23 21:20:44 +00:00
|
|
|
return ret
|
|
|
|
|
|
|
|
def get_success_url(self):
|
2020-09-24 12:58:35 +00:00
|
|
|
return reverse_lazy("participation:team_detail", args=(self.object.pk,))
|
2020-09-23 21:20:44 +00:00
|
|
|
|
2020-09-22 18:41:42 +00:00
|
|
|
|
|
|
|
class JoinTeamView(LoginRequiredMixin, FormView):
|
|
|
|
model = Team
|
|
|
|
form_class = JoinTeamForm
|
|
|
|
extra_context = dict(title=_("Join team"))
|
|
|
|
template_name = "participation/create_team.html"
|
2020-09-23 21:20:44 +00:00
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
2020-09-23 21:20:44 +00:00
|
|
|
registration = user.registration
|
|
|
|
if not registration.participates:
|
2020-09-27 14:35:31 +00:00
|
|
|
raise PermissionDenied(_("You don't participate, so you can't create a team."))
|
2020-09-23 21:20:44 +00:00
|
|
|
elif registration.team:
|
2020-09-27 14:35:31 +00:00
|
|
|
raise PermissionDenied(_("You are already in a team."))
|
|
|
|
return super().dispatch(request, *args, **kwargs)
|
2020-09-23 21:20:44 +00:00
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
@transaction.atomic
|
|
|
|
def form_valid(self, form):
|
2020-09-24 12:58:35 +00:00
|
|
|
self.object = form.instance
|
2020-09-23 21:20:44 +00:00
|
|
|
ret = super().form_valid(form)
|
2020-09-27 14:35:31 +00:00
|
|
|
user = self.request.user
|
|
|
|
registration = user.registration
|
2020-09-23 21:20:44 +00:00
|
|
|
registration.team = form.instance
|
|
|
|
registration.save()
|
2020-10-09 11:49:09 +00:00
|
|
|
get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
|
|
|
|
f"{user.first_name} {user.last_name}")
|
2020-09-23 21:20:44 +00:00
|
|
|
return ret
|
|
|
|
|
|
|
|
def get_success_url(self):
|
2020-09-24 12:58:35 +00:00
|
|
|
return reverse_lazy("participation:team_detail", args=(self.object.pk,))
|
2020-09-24 08:21:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MyTeamDetailView(LoginRequiredMixin, RedirectView):
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
|
|
user = self.request.user
|
|
|
|
registration = user.registration
|
|
|
|
if registration.participates:
|
|
|
|
if registration.team:
|
|
|
|
return reverse_lazy("participation:team_detail", args=(registration.team_id,))
|
|
|
|
raise PermissionDenied(_("You are not in a team."))
|
|
|
|
raise PermissionDenied(_("You don't participate, so you don't have any team."))
|
|
|
|
|
|
|
|
|
2020-10-11 16:44:42 +00:00
|
|
|
class TeamDetailView(LoginRequiredMixin, FormMixin, ProcessFormView, DetailView):
|
2020-09-24 08:21:50 +00:00
|
|
|
model = Team
|
2020-09-24 09:15:54 +00:00
|
|
|
|
2020-10-11 14:30:02 +00:00
|
|
|
def get(self, request, *args, **kwargs):
|
2020-09-27 14:35:31 +00:00
|
|
|
user = request.user
|
2020-10-11 16:44:42 +00:00
|
|
|
self.object = self.get_object()
|
2020-09-27 14:38:17 +00:00
|
|
|
if user.registration.is_admin or user.registration.participates and user.registration.team.pk == kwargs["pk"]:
|
2020-10-11 14:30:02 +00:00
|
|
|
return super().get(request, *args, **kwargs)
|
2020-09-27 14:35:31 +00:00
|
|
|
raise PermissionDenied
|
|
|
|
|
2020-10-11 14:30:02 +00:00
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
|
2020-10-11 16:44:42 +00:00
|
|
|
team = self.get_object()
|
|
|
|
context["request_validation_form"] = RequestValidationForm(self.request.POST or None)
|
|
|
|
context["validation_form"] = ValidateParticipationForm(self.request.POST or None)
|
2020-10-11 14:30:02 +00:00
|
|
|
context["can_validate"] = team.students.count() >= 3 and \
|
2020-10-11 14:49:31 +00:00
|
|
|
all(r.email_confirmed for r in team.students.all()) and \
|
2020-10-11 14:30:02 +00:00
|
|
|
all(r.photo_authorization for r in team.students.all()) and \
|
|
|
|
team.participation.problem
|
|
|
|
|
|
|
|
return context
|
|
|
|
|
2020-10-11 16:44:42 +00:00
|
|
|
def get_form_class(self):
|
|
|
|
if not self.request.POST:
|
|
|
|
return RequestValidationForm
|
|
|
|
elif self.request.POST["_form_type"] == "RequestValidationForm":
|
|
|
|
return RequestValidationForm
|
|
|
|
elif self.request.POST["_form_type"] == "ValidateParticipationForm":
|
|
|
|
return ValidateParticipationForm
|
|
|
|
return None
|
|
|
|
|
|
|
|
def form_valid(self, form):
|
|
|
|
self.object = self.get_object()
|
|
|
|
if isinstance(form, RequestValidationForm):
|
|
|
|
if not self.request.user.registration.participates:
|
|
|
|
form.add_error(None, _("You don't participate, so you can't request the validation of the team."))
|
|
|
|
return self.form_invalid(form)
|
|
|
|
if self.object.participation.valid is not None:
|
|
|
|
form.add_error(None, _("The validation of the team is already done or pending."))
|
|
|
|
return self.form_invalid(form)
|
|
|
|
|
|
|
|
self.object.participation.valid = False
|
|
|
|
self.object.participation.save()
|
|
|
|
|
|
|
|
for admin in AdminRegistration.objects.all():
|
|
|
|
mail_context = dict(user=admin.user, team=self.object)
|
|
|
|
mail_plain = render_to_string("participation/mails/request_validation.txt", mail_context)
|
|
|
|
mail_html = render_to_string("participation/mails/request_validation.html", mail_context)
|
|
|
|
admin.user.email_user("[Corres2math] Validation d'équipe", mail_plain, html_message=mail_html)
|
|
|
|
elif isinstance(form, ValidateParticipationForm):
|
|
|
|
if not self.request.user.registration.is_admin:
|
|
|
|
form.add_error(None, _("You are not an administrator."))
|
|
|
|
return self.form_invalid(form)
|
|
|
|
elif self.object.participation.valid is not False:
|
|
|
|
form.add_error(None, _("This team has no pending validation."))
|
|
|
|
return self.form_invalid(form)
|
|
|
|
|
|
|
|
if "validate" in self.request.POST:
|
|
|
|
self.object.participation.valid = True
|
|
|
|
self.object.participation.save()
|
2020-10-11 17:06:32 +00:00
|
|
|
mail_context = dict(team=self.object, message=form.cleaned_data["message"])
|
|
|
|
mail_plain = render_to_string("participation/mails/team_validated.txt", mail_context)
|
|
|
|
mail_html = render_to_string("participation/mails/team_validated.html", mail_context)
|
|
|
|
send_mail("[Corres2math] Équipe validée", mail_plain, None,
|
|
|
|
[f"equipe-{self.object.trigram.lower()}@{os.getenv('SYMPA_HOST', 'localhost')}"],
|
|
|
|
html_message=mail_html)
|
2020-10-11 16:44:42 +00:00
|
|
|
elif "invalidate" in self.request.POST:
|
|
|
|
self.object.participation.valid = None
|
|
|
|
self.object.participation.save()
|
2020-10-11 17:06:32 +00:00
|
|
|
mail_context = dict(team=self.object, message=form.cleaned_data["message"])
|
|
|
|
mail_plain = render_to_string("participation/mails/team_not_validated.txt", mail_context)
|
|
|
|
mail_html = render_to_string("participation/mails/team_not_validated.html", mail_context)
|
|
|
|
send_mail("[Corres2math] Équipe non validée", mail_plain, None,
|
|
|
|
[f"equipe-{self.object.trigram.lower()}@{os.getenv('SYMPA_HOST', 'localhost')}"],
|
|
|
|
html_message=mail_html)
|
2020-10-11 16:44:42 +00:00
|
|
|
else:
|
|
|
|
form.add_error(None, _("You must specify if you validate the registration or not."))
|
|
|
|
return self.form_invalid(form)
|
|
|
|
|
|
|
|
return super().form_invalid(form)
|
|
|
|
|
|
|
|
def get_success_url(self):
|
|
|
|
return self.request.path
|
|
|
|
|
2020-09-24 09:15:54 +00:00
|
|
|
|
|
|
|
class TeamUpdateView(LoginRequiredMixin, UpdateView):
|
|
|
|
model = Team
|
|
|
|
form_class = TeamForm
|
|
|
|
template_name = "participation/update_team.html"
|
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
2020-09-27 14:38:17 +00:00
|
|
|
if user.registration.is_admin or user.registration.participates and user.registration.team.pk == kwargs["pk"]:
|
2020-09-27 14:35:31 +00:00
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
raise PermissionDenied
|
|
|
|
|
2020-09-24 09:15:54 +00:00
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
context["participation_form"] = ParticipationForm(data=self.request.POST or None,
|
|
|
|
instance=self.object.participation)
|
|
|
|
return context
|
|
|
|
|
|
|
|
@transaction.atomic
|
|
|
|
def form_valid(self, form):
|
|
|
|
participation_form = ParticipationForm(data=self.request.POST or None, instance=self.object.participation)
|
|
|
|
if not participation_form.is_valid():
|
|
|
|
return self.form_invalid(form)
|
|
|
|
|
|
|
|
participation_form.save()
|
|
|
|
return super().form_valid(form)
|
|
|
|
|
|
|
|
def get_success_url(self):
|
|
|
|
return reverse_lazy("participation:team_detail", args=(self.object.pk,))
|
2020-09-27 12:32:05 +00:00
|
|
|
|
|
|
|
|
2020-09-27 16:40:45 +00:00
|
|
|
class TeamAuthorizationsView(LoginRequiredMixin, DetailView):
|
|
|
|
model = Team
|
|
|
|
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
|
|
|
if user.registration.is_admin or user.registration.participates and user.registration.team.pk == kwargs["pk"]:
|
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
raise PermissionDenied
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
team = self.get_object()
|
|
|
|
output = BytesIO()
|
|
|
|
zf = ZipFile(output, "w")
|
|
|
|
for student in team.students.all():
|
|
|
|
magic = Magic(mime=True)
|
|
|
|
mime_type = magic.from_file("media/" + student.photo_authorization.name)
|
|
|
|
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
|
|
|
zf.write("media/" + student.photo_authorization.name,
|
|
|
|
_("Photo authorization of {student}.{ext}").format(student=str(student), ext=ext))
|
|
|
|
zf.close()
|
|
|
|
response = HttpResponse(content_type="application/zip")
|
2020-10-11 14:30:02 +00:00
|
|
|
response["Content-Disposition"] = "attachment; filename=\"{filename}\"" \
|
2020-09-27 16:40:45 +00:00
|
|
|
.format(filename=_("Photo authorizations of team {trigram}.zip").format(trigram=team.trigram))
|
|
|
|
response.write(output.getvalue())
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2020-09-27 12:32:05 +00:00
|
|
|
class MyParticipationDetailView(LoginRequiredMixin, RedirectView):
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
|
|
user = self.request.user
|
|
|
|
registration = user.registration
|
|
|
|
if registration.participates:
|
|
|
|
if registration.team:
|
|
|
|
return reverse_lazy("participation:participation_detail", args=(registration.team.participation.id,))
|
|
|
|
raise PermissionDenied(_("You are not in a team."))
|
|
|
|
raise PermissionDenied(_("You don't participate, so you don't have any team."))
|
|
|
|
|
|
|
|
|
|
|
|
class ParticipationDetailView(LoginRequiredMixin, DetailView):
|
|
|
|
model = Participation
|
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
2020-10-11 14:00:43 +00:00
|
|
|
if not self.get_object().valid:
|
|
|
|
raise PermissionDenied(_("The team is not validated yet."))
|
2020-10-11 14:30:02 +00:00
|
|
|
if user.registration.is_admin or user.registration.participates \
|
2020-09-27 14:38:17 +00:00
|
|
|
and user.registration.team.participation.pk == kwargs["pk"]:
|
2020-09-27 14:35:31 +00:00
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
raise PermissionDenied
|
|
|
|
|
2020-09-27 12:32:05 +00:00
|
|
|
|
|
|
|
class UploadVideoView(LoginRequiredMixin, UpdateView):
|
|
|
|
model = Video
|
|
|
|
form_class = UploadVideoForm
|
|
|
|
template_name = "participation/upload_video.html"
|
|
|
|
|
2020-09-27 14:35:31 +00:00
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
user = request.user
|
2020-10-11 14:30:02 +00:00
|
|
|
if user.registration.is_admin or user.registration.participates \
|
2020-09-27 14:52:52 +00:00
|
|
|
and user.registration.team.participation.pk == self.get_object().participation.pk:
|
2020-09-27 14:35:31 +00:00
|
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
raise PermissionDenied
|
|
|
|
|
2020-09-27 12:32:05 +00:00
|
|
|
def get_success_url(self):
|
|
|
|
return reverse_lazy("participation:participation_detail", args=(self.object.participation.pk,))
|
2020-10-20 11:06:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CalendarView(SingleTableView):
|
|
|
|
table_class = CalendarTable
|
|
|
|
model = Phase
|
2020-10-20 11:14:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PhaseUpdateView(AdminMixin, UpdateView):
|
|
|
|
model = Phase
|
|
|
|
form_class = PhaseForm
|
2020-10-20 12:21:16 +00:00
|
|
|
|
|
|
|
def get_success_url(self):
|
|
|
|
return reverse_lazy("participation:calendar")
|