1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-06-26 03:57:41 +02:00

Add extra access to juries

This commit is contained in:
Yohann D'ANELLO
2020-05-25 18:27:07 +02:00
parent 522ed088ef
commit 3d9e7136ac
8 changed files with 264 additions and 155 deletions

View File

@ -1,4 +1,5 @@
import os
import random
from django.core.mail import send_mail
from django.db import models
@ -338,6 +339,13 @@ class Pool(models.Model):
verbose_name=_("juries"),
)
extra_access_token = models.CharField(
max_length=64,
default="",
verbose_name=_("extra access token"),
help_text=_("Let other users access to the pool data without logging in."),
)
@property
def problems(self):
"""
@ -361,6 +369,13 @@ class Pool(models.Model):
from member.models import Synthesis
return Synthesis.objects.filter(team__in=self.teams.all(), round=self.round, final=self.tournament.final)
def save(self, **kwargs):
if not self.extra_access_token:
alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789"
code = "".join(random.choice(alphabet) for _ in range(64))
self.extra_access_token = code
super().save(**kwargs)
class Meta:
verbose_name = _("pool")
verbose_name_plural = _("pools")

View File

@ -3,7 +3,7 @@ import zipfile
from datetime import timedelta
from io import BytesIO
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
from django.core.exceptions import PermissionDenied
from django.core.mail import send_mail
from django.db.models import Q
@ -34,13 +34,15 @@ class AdminMixin(LoginRequiredMixin):
return super().dispatch(request, *args, **kwargs)
class OrgaMixin(LoginRequiredMixin):
class OrgaMixin(AccessMixin):
"""
If a view extends this mixin, then the view will be only accessible to administrators or organizers.
"""
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated or not request.user.organizes:
if not request.user.is_authenticated and not request.session["extra_access_token"]:
return self.handle_no_permission()
elif request.user.is_authenticated and not request.user.organizes:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
@ -247,7 +249,7 @@ class TeamDetailView(LoginRequiredMixin, DetailView):
context = super().get_context_data(**kwargs)
context["title"] = _("Information about team")
context["ordered_solutions"] = self.object.solutions.order_by('problem').all()
context["ordered_solutions"] = self.object.solutions.order_by('final', 'problem',).all()
context["team_users_emails"] = [user.email for user in self.object.users.all()]
return context
@ -399,19 +401,22 @@ class SolutionsOrgaListView(OrgaMixin, SingleTableView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["tournaments"] = \
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
if self.request.user.is_authenticated:
context["tournaments"] = \
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
return context
def get_queryset(self):
qs = super().get_queryset()
if not self.request.user.admin:
if self.request.user.is_authenticated and not self.request.user.admin:
if self.request.user in Tournament.get_final().organizers.all():
qs = qs.filter(Q(team__tournament__organizers=self.request.user) | Q(pools__juries=self.request.user)
| Q(final=True))
else:
qs = qs.filter(Q(team__tournament__organizers=self.request.user) | Q(pools__juries=self.request.user))
elif not self.request.user.is_authenticated:
qs = qs.filter(pools__extra_access_token=self.request.session["extra_access_token"])
return qs.order_by('final', 'team__tournament__date_start', 'team__tournament__name', 'team__trigram',
'problem',).distinct()
@ -529,14 +534,15 @@ class SynthesesOrgaListView(OrgaMixin, SingleTableView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["tournaments"] = \
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
if self.request.user.is_authenticated:
context["tournaments"] = \
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
return context
def get_queryset(self):
qs = super().get_queryset()
if not self.request.user.admin:
if self.request.user.is_authenticated and not self.request.user.admin:
if self.request.user in Tournament.get_final().organizers.all():
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
| Q(team__pools__juries=self.request.user)
@ -544,11 +550,18 @@ class SynthesesOrgaListView(OrgaMixin, SingleTableView):
else:
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
| Q(team__pools__juries=self.request.user))
elif not self.request.user.is_authenticated:
pool = Pool.objects.filter(extra_access_token=self.request.session["extra_access_token"])
if pool.exists():
pool = pool.get()
qs = qs.filter(team__pools=pool, final=pool.tournament.final)
else:
qs = qs.none()
return qs.order_by('final', 'team__tournament__date_start', 'team__tournament__name', 'team__trigram',
'round', 'source',).distinct()
class PoolListView(LoginRequiredMixin, SingleTableView):
class PoolListView(SingleTableView):
"""
View the list of visible pools.
Admins see all, juries see their own pools, organizers see the pools of their tournaments.
@ -560,10 +573,13 @@ class PoolListView(LoginRequiredMixin, SingleTableView):
def get_queryset(self):
qs = super().get_queryset()
user = self.request.user
if not user.admin and user.organizes:
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
elif user.participates:
qs = qs.filter(teams=user.team)
if user.is_authenticated:
if not user.admin and user.organizes:
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
elif user.participates:
qs = qs.filter(teams=user.team)
else:
qs = qs.filter(extra_access_token=self.request.session["extra_access_token"])
qs = qs.distinct().order_by('id')
return qs
@ -581,7 +597,7 @@ class PoolCreateView(AdminMixin, CreateView):
return reverse_lazy("tournament:pools")
class PoolDetailView(LoginRequiredMixin, DetailView):
class PoolDetailView(DetailView):
"""
See the detail of a pool.
Teams and juries can download here defended solutions of the pool.
@ -597,10 +613,13 @@ class PoolDetailView(LoginRequiredMixin, DetailView):
def get_queryset(self):
qs = super().get_queryset()
user = self.request.user
if not user.admin and user.organizes:
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
elif user.participates:
qs = qs.filter(teams=user.team)
if user.is_authenticated:
if not user.admin and user.organizes:
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
elif user.participates:
qs = qs.filter(teams=user.team)
else:
qs = qs.filter(extra_access_token=self.request.session["extra_access_token"])
return qs.distinct()
def post(self, request, *args, **kwargs):
@ -608,7 +627,8 @@ class PoolDetailView(LoginRequiredMixin, DetailView):
pool = self.get_object()
if "solutions_zip" in request.POST:
if user.participates and pool.round == 2 and pool.tournament.date_solutions_2 > timezone.now():
if user.is_authenticated and user.participates and pool.round == 2\
and pool.tournament.date_solutions_2 > timezone.now():
raise PermissionDenied
out = BytesIO()
@ -624,10 +644,7 @@ class PoolDetailView(LoginRequiredMixin, DetailView):
.format(_("Solutions of a pool for the round {round} of the tournament {tournament}.zip")
.format(round=pool.round, tournament=str(pool.tournament)).replace(" ", "%20"))
return resp
elif "syntheses_zip" in request.POST and user.organizes:
if user.participates and pool.round == 2 and pool.tournament.date_solutions_2 > timezone.now():
raise PermissionDenied
elif "syntheses_zip" in request.POST and (not user.is_authenticated or user.organizes):
out = BytesIO()
zf = zipfile.ZipFile(out, "w")