Add extra access to juries
This commit is contained in:
parent
522ed088ef
commit
3d9e7136ac
|
@ -1,6 +1,6 @@
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin, AccessMixin
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
@ -13,7 +13,7 @@ from django.views import View
|
||||||
from django.views.generic import CreateView, UpdateView, DetailView, FormView
|
from django.views.generic import CreateView, UpdateView, DetailView, FormView
|
||||||
from django_tables2 import SingleTableView
|
from django_tables2 import SingleTableView
|
||||||
from tournament.forms import TeamForm, JoinTeam
|
from tournament.forms import TeamForm, JoinTeam
|
||||||
from tournament.models import Team, Tournament
|
from tournament.models import Team, Tournament, Pool
|
||||||
from tournament.views import AdminMixin, TeamMixin, OrgaMixin
|
from tournament.views import AdminMixin, TeamMixin, OrgaMixin
|
||||||
|
|
||||||
from .forms import SignUpForm, TFJMUserForm, AdminUserForm, CoachUserForm
|
from .forms import SignUpForm, TFJMUserForm, AdminUserForm, CoachUserForm
|
||||||
|
@ -177,7 +177,7 @@ class MyTeamView(TeamMixin, View):
|
||||||
return redirect("tournament:team_detail", pk=request.user.team.pk)
|
return redirect("tournament:team_detail", pk=request.user.team.pk)
|
||||||
|
|
||||||
|
|
||||||
class DocumentView(LoginRequiredMixin, View):
|
class DocumentView(AccessMixin, View):
|
||||||
"""
|
"""
|
||||||
View a PDF document, if we have the right.
|
View a PDF document, if we have the right.
|
||||||
|
|
||||||
|
@ -194,14 +194,11 @@ class DocumentView(LoginRequiredMixin, View):
|
||||||
raise Http404(_("No %(verbose_name)s found matching the query") %
|
raise Http404(_("No %(verbose_name)s found matching the query") %
|
||||||
{'verbose_name': Document._meta.verbose_name})
|
{'verbose_name': Document._meta.verbose_name})
|
||||||
|
|
||||||
|
if request.user.is_authenticated:
|
||||||
grant = request.user.admin
|
grant = request.user.admin
|
||||||
|
|
||||||
if isinstance(doc, Solution) or isinstance(doc, Synthesis) or isinstance(doc, MotivationLetter):
|
if isinstance(doc, Solution) or isinstance(doc, Synthesis) or isinstance(doc, MotivationLetter):
|
||||||
grant = grant or doc.team == request.user.team or request.user in doc.team.tournament.organizers.all()
|
grant = grant or doc.team == request.user.team or request.user in doc.tournament.organizers.all()
|
||||||
grant = grant or (doc.team.selected_for_final and request.user in Tournament.get_final().organizers.all())
|
|
||||||
|
|
||||||
if isinstance(doc, Synthesis) and request.user.organizes:
|
|
||||||
grant = True
|
|
||||||
|
|
||||||
if isinstance(doc, Solution):
|
if isinstance(doc, Solution):
|
||||||
for pool in doc.pools.all():
|
for pool in doc.pools.all():
|
||||||
|
@ -212,6 +209,23 @@ class DocumentView(LoginRequiredMixin, View):
|
||||||
continue
|
continue
|
||||||
if self.request.user.team in pool.teams.all():
|
if self.request.user.team in pool.teams.all():
|
||||||
grant = True
|
grant = True
|
||||||
|
elif isinstance(doc, Synthesis):
|
||||||
|
for pool in request.user.pools.all(): # If the user is a jury in the pool
|
||||||
|
if doc.team in pool.teams.all() and doc.final == pool.tournament.final:
|
||||||
|
grant = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pool = Pool.objects.filter(extra_access_token=self.request.session["extra_access_token"])
|
||||||
|
if pool.exists():
|
||||||
|
pool = pool.get()
|
||||||
|
if isinstance(doc, Solution):
|
||||||
|
grant = doc in pool.solutions.all()
|
||||||
|
elif isinstance(doc, Synthesis):
|
||||||
|
grant = doc.team in pool.teams.all() and doc.final == pool.tournament.final
|
||||||
|
else:
|
||||||
|
grant = False
|
||||||
|
else:
|
||||||
|
grant = False
|
||||||
|
|
||||||
if not grant:
|
if not grant:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -338,6 +339,13 @@ class Pool(models.Model):
|
||||||
verbose_name=_("juries"),
|
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
|
@property
|
||||||
def problems(self):
|
def problems(self):
|
||||||
"""
|
"""
|
||||||
|
@ -361,6 +369,13 @@ class Pool(models.Model):
|
||||||
from member.models import Synthesis
|
from member.models import Synthesis
|
||||||
return Synthesis.objects.filter(team__in=self.teams.all(), round=self.round, final=self.tournament.final)
|
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:
|
class Meta:
|
||||||
verbose_name = _("pool")
|
verbose_name = _("pool")
|
||||||
verbose_name_plural = _("pools")
|
verbose_name_plural = _("pools")
|
||||||
|
|
|
@ -3,7 +3,7 @@ import zipfile
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from io import BytesIO
|
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.exceptions import PermissionDenied
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
@ -34,13 +34,15 @@ class AdminMixin(LoginRequiredMixin):
|
||||||
return super().dispatch(request, *args, **kwargs)
|
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.
|
If a view extends this mixin, then the view will be only accessible to administrators or organizers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
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
|
raise PermissionDenied
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -247,7 +249,7 @@ class TeamDetailView(LoginRequiredMixin, DetailView):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
context["title"] = _("Information about team")
|
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()]
|
context["team_users_emails"] = [user.email for user in self.object.users.all()]
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@ -399,6 +401,7 @@ class SolutionsOrgaListView(OrgaMixin, SingleTableView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
if self.request.user.is_authenticated:
|
||||||
context["tournaments"] = \
|
context["tournaments"] = \
|
||||||
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
||||||
|
|
||||||
|
@ -406,12 +409,14 @@ class SolutionsOrgaListView(OrgaMixin, SingleTableView):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
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():
|
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)
|
qs = qs.filter(Q(team__tournament__organizers=self.request.user) | Q(pools__juries=self.request.user)
|
||||||
| Q(final=True))
|
| Q(final=True))
|
||||||
else:
|
else:
|
||||||
qs = qs.filter(Q(team__tournament__organizers=self.request.user) | Q(pools__juries=self.request.user))
|
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',
|
return qs.order_by('final', 'team__tournament__date_start', 'team__tournament__name', 'team__trigram',
|
||||||
'problem',).distinct()
|
'problem',).distinct()
|
||||||
|
|
||||||
|
@ -529,6 +534,7 @@ class SynthesesOrgaListView(OrgaMixin, SingleTableView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
if self.request.user.is_authenticated:
|
||||||
context["tournaments"] = \
|
context["tournaments"] = \
|
||||||
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
||||||
|
|
||||||
|
@ -536,7 +542,7 @@ class SynthesesOrgaListView(OrgaMixin, SingleTableView):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
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():
|
if self.request.user in Tournament.get_final().organizers.all():
|
||||||
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
|
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
|
||||||
| Q(team__pools__juries=self.request.user)
|
| Q(team__pools__juries=self.request.user)
|
||||||
|
@ -544,11 +550,18 @@ class SynthesesOrgaListView(OrgaMixin, SingleTableView):
|
||||||
else:
|
else:
|
||||||
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
|
qs = qs.filter(Q(team__tournament__organizers=self.request.user)
|
||||||
| Q(team__pools__juries=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',
|
return qs.order_by('final', 'team__tournament__date_start', 'team__tournament__name', 'team__trigram',
|
||||||
'round', 'source',).distinct()
|
'round', 'source',).distinct()
|
||||||
|
|
||||||
|
|
||||||
class PoolListView(LoginRequiredMixin, SingleTableView):
|
class PoolListView(SingleTableView):
|
||||||
"""
|
"""
|
||||||
View the list of visible pools.
|
View the list of visible pools.
|
||||||
Admins see all, juries see their own pools, organizers see the pools of their tournaments.
|
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):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
|
if user.is_authenticated:
|
||||||
if not user.admin and user.organizes:
|
if not user.admin and user.organizes:
|
||||||
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
|
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
|
||||||
elif user.participates:
|
elif user.participates:
|
||||||
qs = qs.filter(teams=user.team)
|
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')
|
qs = qs.distinct().order_by('id')
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
@ -581,7 +597,7 @@ class PoolCreateView(AdminMixin, CreateView):
|
||||||
return reverse_lazy("tournament:pools")
|
return reverse_lazy("tournament:pools")
|
||||||
|
|
||||||
|
|
||||||
class PoolDetailView(LoginRequiredMixin, DetailView):
|
class PoolDetailView(DetailView):
|
||||||
"""
|
"""
|
||||||
See the detail of a pool.
|
See the detail of a pool.
|
||||||
Teams and juries can download here defended solutions of the pool.
|
Teams and juries can download here defended solutions of the pool.
|
||||||
|
@ -597,10 +613,13 @@ class PoolDetailView(LoginRequiredMixin, DetailView):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
|
if user.is_authenticated:
|
||||||
if not user.admin and user.organizes:
|
if not user.admin and user.organizes:
|
||||||
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
|
qs = qs.filter(Q(juries=user) | Q(teams__tournament__organizers=user))
|
||||||
elif user.participates:
|
elif user.participates:
|
||||||
qs = qs.filter(teams=user.team)
|
qs = qs.filter(teams=user.team)
|
||||||
|
else:
|
||||||
|
qs = qs.filter(extra_access_token=self.request.session["extra_access_token"])
|
||||||
return qs.distinct()
|
return qs.distinct()
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
@ -608,7 +627,8 @@ class PoolDetailView(LoginRequiredMixin, DetailView):
|
||||||
pool = self.get_object()
|
pool = self.get_object()
|
||||||
|
|
||||||
if "solutions_zip" in request.POST:
|
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
|
raise PermissionDenied
|
||||||
|
|
||||||
out = BytesIO()
|
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(_("Solutions of a pool for the round {round} of the tournament {tournament}.zip")
|
||||||
.format(round=pool.round, tournament=str(pool.tournament)).replace(" ", "%20"))
|
.format(round=pool.round, tournament=str(pool.tournament)).replace(" ", "%20"))
|
||||||
return resp
|
return resp
|
||||||
elif "syntheses_zip" in request.POST and user.organizes:
|
elif "syntheses_zip" in request.POST and (not user.is_authenticated or user.organizes):
|
||||||
if user.participates and pool.round == 2 and pool.tournament.date_solutions_2 > timezone.now():
|
|
||||||
raise PermissionDenied
|
|
||||||
|
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
zf = zipfile.ZipFile(out, "w")
|
zf = zipfile.ZipFile(out, "w")
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TFJM2\n"
|
"Project-Id-Version: TFJM2\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-05-12 18:25+0200\n"
|
"POT-Creation-Date: 2020-05-25 18:23+0200\n"
|
||||||
"PO-Revision-Date: 2020-04-29 02:30+0000\n"
|
"PO-Revision-Date: 2020-04-29 02:30+0000\n"
|
||||||
"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
|
"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
|
||||||
"Language-Team: fr <LL@li.org>\n"
|
"Language-Team: fr <LL@li.org>\n"
|
||||||
|
@ -44,11 +44,11 @@ msgstr "Adresse électronique"
|
||||||
|
|
||||||
#: apps/member/models.py:22
|
#: apps/member/models.py:22
|
||||||
msgid "This should be valid and will be controlled."
|
msgid "This should be valid and will be controlled."
|
||||||
msgstr ""
|
msgstr "Elle doit être valide et sera contrôlée."
|
||||||
|
|
||||||
#: apps/member/models.py:30 apps/member/models.py:244 apps/member/models.py:263
|
#: apps/member/models.py:30 apps/member/models.py:244 apps/member/models.py:263
|
||||||
#: apps/member/models.py:306 apps/tournament/models.py:285
|
#: apps/member/models.py:306 apps/tournament/models.py:286
|
||||||
#: apps/tournament/models.py:385 templates/member/tfjmuser_detail.html:16
|
#: apps/tournament/models.py:400 templates/member/tfjmuser_detail.html:16
|
||||||
msgid "team"
|
msgid "team"
|
||||||
msgstr "équipe"
|
msgstr "équipe"
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ msgstr "téléphone du responsable"
|
||||||
msgid "responsible email"
|
msgid "responsible email"
|
||||||
msgstr "email du responsable"
|
msgstr "email du responsable"
|
||||||
|
|
||||||
#: apps/member/models.py:129 apps/tournament/models.py:44
|
#: apps/member/models.py:129 apps/tournament/models.py:45
|
||||||
#: templates/member/tfjmuser_detail.html:67
|
#: templates/member/tfjmuser_detail.html:67
|
||||||
#: templates/tournament/tournament_detail.html:42
|
#: templates/tournament/tournament_detail.html:42
|
||||||
msgid "description"
|
msgid "description"
|
||||||
|
@ -138,13 +138,13 @@ msgstr "Administrateur"
|
||||||
msgid "Organizer"
|
msgid "Organizer"
|
||||||
msgstr "Organisateur"
|
msgstr "Organisateur"
|
||||||
|
|
||||||
#: apps/member/models.py:144 apps/tournament/models.py:89
|
#: apps/member/models.py:144 apps/tournament/models.py:90
|
||||||
#: apps/tournament/models.py:214
|
#: apps/tournament/models.py:215
|
||||||
msgid "year"
|
msgid "year"
|
||||||
msgstr "année"
|
msgstr "année"
|
||||||
|
|
||||||
#: apps/member/models.py:171 apps/member/models.py:214
|
#: apps/member/models.py:171 apps/member/models.py:214
|
||||||
#: apps/tournament/models.py:378
|
#: apps/tournament/models.py:393
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "utilisateur"
|
msgstr "utilisateur"
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ msgstr "Autorisation de droit à l'image"
|
||||||
msgid "Sanitary plug"
|
msgid "Sanitary plug"
|
||||||
msgstr "Fiche sanitaire"
|
msgstr "Fiche sanitaire"
|
||||||
|
|
||||||
#: apps/member/models.py:223 apps/tournament/models.py:396
|
#: apps/member/models.py:223 apps/tournament/models.py:411
|
||||||
msgid "Scholarship"
|
msgid "Scholarship"
|
||||||
msgstr "Bourse"
|
msgstr "Bourse"
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ msgstr "solution pour la finale"
|
||||||
msgid "solution"
|
msgid "solution"
|
||||||
msgstr "solution"
|
msgstr "solution"
|
||||||
|
|
||||||
#: apps/member/models.py:286 apps/tournament/models.py:324
|
#: apps/member/models.py:286 apps/tournament/models.py:325
|
||||||
msgid "solutions"
|
msgid "solutions"
|
||||||
msgstr "solutions"
|
msgstr "solutions"
|
||||||
|
|
||||||
|
@ -253,15 +253,15 @@ msgstr "Rapporteur"
|
||||||
msgid "source"
|
msgid "source"
|
||||||
msgstr "source"
|
msgstr "source"
|
||||||
|
|
||||||
#: apps/member/models.py:320 apps/tournament/models.py:329
|
#: apps/member/models.py:320 apps/tournament/models.py:330
|
||||||
msgid "Round 1"
|
msgid "Round 1"
|
||||||
msgstr "Tour 1"
|
msgstr "Tour 1"
|
||||||
|
|
||||||
#: apps/member/models.py:321 apps/tournament/models.py:330
|
#: apps/member/models.py:321 apps/tournament/models.py:331
|
||||||
msgid "Round 2"
|
msgid "Round 2"
|
||||||
msgstr "Tour 2"
|
msgstr "Tour 2"
|
||||||
|
|
||||||
#: apps/member/models.py:323 apps/tournament/models.py:332
|
#: apps/member/models.py:323 apps/tournament/models.py:333
|
||||||
#: templates/tournament/pool_detail.html:18
|
#: templates/tournament/pool_detail.html:18
|
||||||
msgid "round"
|
msgid "round"
|
||||||
msgstr "tour"
|
msgstr "tour"
|
||||||
|
@ -303,40 +303,45 @@ msgstr "configuration"
|
||||||
msgid "configurations"
|
msgid "configurations"
|
||||||
msgstr "configurations"
|
msgstr "configurations"
|
||||||
|
|
||||||
#: apps/member/views.py:100 apps/member/views.py:140
|
#: apps/member/views.py:105 apps/member/views.py:145
|
||||||
msgid "You can't organize and participate at the same time."
|
msgid "You can't organize and participate at the same time."
|
||||||
msgstr "Vous ne pouvez pas organiser et participer en même temps."
|
msgstr "Vous ne pouvez pas organiser et participer en même temps."
|
||||||
|
|
||||||
#: apps/member/views.py:104 apps/member/views.py:144
|
#: apps/member/views.py:109 apps/member/views.py:149
|
||||||
msgid "You are already in a team."
|
msgid "You are already in a team."
|
||||||
msgstr "Vous êtes déjà dans une équipe."
|
msgstr "Vous êtes déjà dans une équipe."
|
||||||
|
|
||||||
#: apps/member/views.py:148
|
#: apps/member/views.py:153
|
||||||
msgid "This team is full of coachs."
|
msgid "This team is full of coachs."
|
||||||
msgstr "Cette équipe est pleine en encadrants."
|
msgstr "Cette équipe est pleine en encadrants."
|
||||||
|
|
||||||
#: apps/member/views.py:152
|
#: apps/member/views.py:157
|
||||||
msgid "This team is full of participants."
|
msgid "This team is full of participants."
|
||||||
msgstr "Cette équipe est pleine en participants."
|
msgstr "Cette équipe est pleine en participants."
|
||||||
|
|
||||||
#: apps/member/views.py:156
|
#: apps/member/views.py:161
|
||||||
msgid "This team is already validated or waiting for validation."
|
msgid "This team is already validated or waiting for validation."
|
||||||
msgstr "L'équipe est déjà en attente de validation."
|
msgstr "L'équipe est déjà en attente de validation."
|
||||||
|
|
||||||
#: apps/member/views.py:220 templates/base.html:81
|
#: apps/member/views.py:194
|
||||||
|
#, python-format
|
||||||
|
msgid "No %(verbose_name)s found matching the query"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/member/views.py:244 templates/base.html:81
|
||||||
msgid "All profiles"
|
msgid "All profiles"
|
||||||
msgstr "Tous les profils"
|
msgstr "Tous les profils"
|
||||||
|
|
||||||
#: apps/member/views.py:232 templates/base.html:80
|
#: apps/member/views.py:256 templates/base.html:80
|
||||||
msgid "Orphaned profiles"
|
msgid "Orphaned profiles"
|
||||||
msgstr "Profils orphelins"
|
msgstr "Profils orphelins"
|
||||||
|
|
||||||
#: apps/member/views.py:244 apps/tournament/forms.py:23 templates/base.html:83
|
#: apps/member/views.py:268 apps/tournament/forms.py:23 templates/base.html:83
|
||||||
msgid "Organizers"
|
msgid "Organizers"
|
||||||
msgstr "Organisateurs"
|
msgstr "Organisateurs"
|
||||||
|
|
||||||
#: apps/tournament/apps.py:10 apps/tournament/models.py:134
|
#: apps/tournament/apps.py:10 apps/tournament/models.py:135
|
||||||
#: apps/tournament/models.py:182 apps/tournament/tables.py:110
|
#: apps/tournament/models.py:183 apps/tournament/tables.py:110
|
||||||
#: templates/tournament/pool_detail.html:21
|
#: templates/tournament/pool_detail.html:21
|
||||||
#: templates/tournament/team_detail.html:21
|
#: templates/tournament/team_detail.html:21
|
||||||
msgid "tournament"
|
msgid "tournament"
|
||||||
|
@ -400,7 +405,8 @@ msgstr "Problème n°%(problem)d"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please keep filesize under %(max_size)s. Current filesize %(current_size)s"
|
"Please keep filesize under %(max_size)s. Current filesize %(current_size)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Merci de ne pas dépasser les %(max_size)s. Le fichier envoyé pèse %(current_size)s."
|
"Merci de ne pas dépasser les %(max_size)s. Le fichier envoyé pèse "
|
||||||
|
"%(current_size)s."
|
||||||
|
|
||||||
#: apps/tournament/forms.py:157 apps/tournament/forms.py:181
|
#: apps/tournament/forms.py:157 apps/tournament/forms.py:181
|
||||||
msgid "The file should be a PDF file."
|
msgid "The file should be a PDF file."
|
||||||
|
@ -435,16 +441,16 @@ msgstr "Équipe 3"
|
||||||
msgid "Problem defended by team 3"
|
msgid "Problem defended by team 3"
|
||||||
msgstr "Problème défendu par l'équipe 3"
|
msgstr "Problème défendu par l'équipe 3"
|
||||||
|
|
||||||
#: apps/tournament/models.py:18 apps/tournament/models.py:169
|
#: apps/tournament/models.py:19 apps/tournament/models.py:170
|
||||||
#: templates/tournament/team_detail.html:12
|
#: templates/tournament/team_detail.html:12
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr "nom"
|
msgstr "nom"
|
||||||
|
|
||||||
#: apps/tournament/models.py:24 templates/tournament/tournament_detail.html:12
|
#: apps/tournament/models.py:25 templates/tournament/tournament_detail.html:12
|
||||||
msgid "organizers"
|
msgid "organizers"
|
||||||
msgstr "organisateurs"
|
msgstr "organisateurs"
|
||||||
|
|
||||||
#: apps/tournament/models.py:25
|
#: apps/tournament/models.py:26
|
||||||
msgid ""
|
msgid ""
|
||||||
"List of all organizers that can see and manipulate data of the tournament "
|
"List of all organizers that can see and manipulate data of the tournament "
|
||||||
"and the teams."
|
"and the teams."
|
||||||
|
@ -452,71 +458,71 @@ msgstr ""
|
||||||
"Liste des organisateurs qui peuvent manipuler les données du tournoi et des "
|
"Liste des organisateurs qui peuvent manipuler les données du tournoi et des "
|
||||||
"équipes."
|
"équipes."
|
||||||
|
|
||||||
#: apps/tournament/models.py:29 templates/tournament/tournament_detail.html:15
|
#: apps/tournament/models.py:30 templates/tournament/tournament_detail.html:15
|
||||||
msgid "size"
|
msgid "size"
|
||||||
msgstr "taille"
|
msgstr "taille"
|
||||||
|
|
||||||
#: apps/tournament/models.py:30
|
#: apps/tournament/models.py:31
|
||||||
msgid "Number of teams that are allowed to join the tournament."
|
msgid "Number of teams that are allowed to join the tournament."
|
||||||
msgstr "Nombre d'équipes qui sont autorisées à rejoindre le tournoi."
|
msgstr "Nombre d'équipes qui sont autorisées à rejoindre le tournoi."
|
||||||
|
|
||||||
#: apps/tournament/models.py:35 templates/tournament/tournament_detail.html:18
|
#: apps/tournament/models.py:36 templates/tournament/tournament_detail.html:18
|
||||||
msgid "place"
|
msgid "place"
|
||||||
msgstr "lieu"
|
msgstr "lieu"
|
||||||
|
|
||||||
#: apps/tournament/models.py:39 templates/tournament/tournament_detail.html:21
|
#: apps/tournament/models.py:40 templates/tournament/tournament_detail.html:21
|
||||||
msgid "price"
|
msgid "price"
|
||||||
msgstr "prix"
|
msgstr "prix"
|
||||||
|
|
||||||
#: apps/tournament/models.py:40
|
#: apps/tournament/models.py:41
|
||||||
msgid "Price asked to participants. Free with a scholarship."
|
msgid "Price asked to participants. Free with a scholarship."
|
||||||
msgstr "Prix demandé par participant. Gratuit pour les boursiers."
|
msgstr "Prix demandé par participant. Gratuit pour les boursiers."
|
||||||
|
|
||||||
#: apps/tournament/models.py:49
|
#: apps/tournament/models.py:50
|
||||||
msgid "date start"
|
msgid "date start"
|
||||||
msgstr "date de début"
|
msgstr "date de début"
|
||||||
|
|
||||||
#: apps/tournament/models.py:54
|
#: apps/tournament/models.py:55
|
||||||
msgid "date end"
|
msgid "date end"
|
||||||
msgstr "date de fin"
|
msgstr "date de fin"
|
||||||
|
|
||||||
#: apps/tournament/models.py:59 templates/tournament/tournament_detail.html:27
|
#: apps/tournament/models.py:60 templates/tournament/tournament_detail.html:27
|
||||||
msgid "date of registration closing"
|
msgid "date of registration closing"
|
||||||
msgstr "date de clôture des inscriptions"
|
msgstr "date de clôture des inscriptions"
|
||||||
|
|
||||||
#: apps/tournament/models.py:64 templates/tournament/tournament_detail.html:30
|
#: apps/tournament/models.py:65 templates/tournament/tournament_detail.html:30
|
||||||
msgid "date of maximal solution submission"
|
msgid "date of maximal solution submission"
|
||||||
msgstr "date d'envoi maximal des solutions"
|
msgstr "date d'envoi maximal des solutions"
|
||||||
|
|
||||||
#: apps/tournament/models.py:69 templates/tournament/tournament_detail.html:33
|
#: apps/tournament/models.py:70 templates/tournament/tournament_detail.html:33
|
||||||
msgid "date of maximal syntheses submission for the first round"
|
msgid "date of maximal syntheses submission for the first round"
|
||||||
msgstr "date d'envoi maximal des notes de synthèses du premier tour"
|
msgstr "date d'envoi maximal des notes de synthèses du premier tour"
|
||||||
|
|
||||||
#: apps/tournament/models.py:74 templates/tournament/tournament_detail.html:36
|
#: apps/tournament/models.py:75 templates/tournament/tournament_detail.html:36
|
||||||
msgid "date when solutions of round 2 are available"
|
msgid "date when solutions of round 2 are available"
|
||||||
msgstr "date à partir de laquelle les solutions du tour 2 sont disponibles"
|
msgstr "date à partir de laquelle les solutions du tour 2 sont disponibles"
|
||||||
|
|
||||||
#: apps/tournament/models.py:79 templates/tournament/tournament_detail.html:39
|
#: apps/tournament/models.py:80 templates/tournament/tournament_detail.html:39
|
||||||
msgid "date of maximal syntheses submission for the second round"
|
msgid "date of maximal syntheses submission for the second round"
|
||||||
msgstr "date d'envoi maximal des notes de synthèses pour le second tour"
|
msgstr "date d'envoi maximal des notes de synthèses pour le second tour"
|
||||||
|
|
||||||
#: apps/tournament/models.py:83
|
#: apps/tournament/models.py:84
|
||||||
msgid "final tournament"
|
msgid "final tournament"
|
||||||
msgstr "finale"
|
msgstr "finale"
|
||||||
|
|
||||||
#: apps/tournament/models.py:84
|
#: apps/tournament/models.py:85
|
||||||
msgid "It should be only one final tournament."
|
msgid "It should be only one final tournament."
|
||||||
msgstr "Il ne doit y avoir qu'une seule finale."
|
msgstr "Il ne doit y avoir qu'une seule finale."
|
||||||
|
|
||||||
#: apps/tournament/models.py:135
|
#: apps/tournament/models.py:136
|
||||||
msgid "tournaments"
|
msgid "tournaments"
|
||||||
msgstr "tournois"
|
msgstr "tournois"
|
||||||
|
|
||||||
#: apps/tournament/models.py:174 templates/tournament/team_detail.html:15
|
#: apps/tournament/models.py:175 templates/tournament/team_detail.html:15
|
||||||
msgid "trigram"
|
msgid "trigram"
|
||||||
msgstr "trigramme"
|
msgstr "trigramme"
|
||||||
|
|
||||||
#: apps/tournament/models.py:175
|
#: apps/tournament/models.py:176
|
||||||
msgid ""
|
msgid ""
|
||||||
"The trigram should be composed of 3 capitalize letters, that is a funny "
|
"The trigram should be composed of 3 capitalize letters, that is a funny "
|
||||||
"acronym for the team."
|
"acronym for the team."
|
||||||
|
@ -524,89 +530,97 @@ msgstr ""
|
||||||
"Le trigramme doit être composé de trois lettres en majuscule, qui doit être "
|
"Le trigramme doit être composé de trois lettres en majuscule, qui doit être "
|
||||||
"un acronyme amusant représentant l'équipe."
|
"un acronyme amusant représentant l'équipe."
|
||||||
|
|
||||||
#: apps/tournament/models.py:183
|
#: apps/tournament/models.py:184
|
||||||
msgid "The tournament where the team is registered."
|
msgid "The tournament where the team is registered."
|
||||||
msgstr "Le tournoi où l'équipe est inscrite."
|
msgstr "Le tournoi où l'équipe est inscrite."
|
||||||
|
|
||||||
#: apps/tournament/models.py:188
|
#: apps/tournament/models.py:189
|
||||||
msgid "inscription date"
|
msgid "inscription date"
|
||||||
msgstr "date d'inscription"
|
msgstr "date d'inscription"
|
||||||
|
|
||||||
#: apps/tournament/models.py:194 apps/tournament/models.py:405
|
#: apps/tournament/models.py:195 apps/tournament/models.py:420
|
||||||
msgid "Registration not validated"
|
msgid "Registration not validated"
|
||||||
msgstr "Inscription non validée"
|
msgstr "Inscription non validée"
|
||||||
|
|
||||||
#: apps/tournament/models.py:195 apps/tournament/models.py:406
|
#: apps/tournament/models.py:196 apps/tournament/models.py:421
|
||||||
msgid "Waiting for validation"
|
msgid "Waiting for validation"
|
||||||
msgstr "En attente de validation"
|
msgstr "En attente de validation"
|
||||||
|
|
||||||
#: apps/tournament/models.py:196 apps/tournament/models.py:407
|
#: apps/tournament/models.py:197 apps/tournament/models.py:422
|
||||||
msgid "Registration validated"
|
msgid "Registration validated"
|
||||||
msgstr "Inscription validée"
|
msgstr "Inscription validée"
|
||||||
|
|
||||||
#: apps/tournament/models.py:198 apps/tournament/models.py:409
|
#: apps/tournament/models.py:199 apps/tournament/models.py:424
|
||||||
#: templates/tournament/team_detail.html:32
|
#: templates/tournament/team_detail.html:32
|
||||||
msgid "validation status"
|
msgid "validation status"
|
||||||
msgstr "statut de validation"
|
msgstr "statut de validation"
|
||||||
|
|
||||||
#: apps/tournament/models.py:203
|
#: apps/tournament/models.py:204
|
||||||
msgid "selected for final"
|
msgid "selected for final"
|
||||||
msgstr "sélectionnée pour la finale"
|
msgstr "sélectionnée pour la finale"
|
||||||
|
|
||||||
#: apps/tournament/models.py:209 templates/tournament/team_detail.html:18
|
#: apps/tournament/models.py:210 templates/tournament/team_detail.html:18
|
||||||
msgid "access code"
|
msgid "access code"
|
||||||
msgstr "code d'accès"
|
msgstr "code d'accès"
|
||||||
|
|
||||||
#: apps/tournament/models.py:286 apps/tournament/models.py:318
|
#: apps/tournament/models.py:287 apps/tournament/models.py:319
|
||||||
#: templates/tournament/pool_detail.html:15
|
#: templates/tournament/pool_detail.html:15
|
||||||
msgid "teams"
|
msgid "teams"
|
||||||
msgstr "équipes"
|
msgstr "équipes"
|
||||||
|
|
||||||
#: apps/tournament/models.py:338 templates/tournament/pool_detail.html:12
|
#: apps/tournament/models.py:339 templates/tournament/pool_detail.html:12
|
||||||
msgid "juries"
|
msgid "juries"
|
||||||
msgstr "jurys"
|
msgstr "jurys"
|
||||||
|
|
||||||
#: apps/tournament/models.py:365
|
#: apps/tournament/models.py:345
|
||||||
|
msgid "extra access token"
|
||||||
|
msgstr "code d'accès spécial"
|
||||||
|
|
||||||
|
#: apps/tournament/models.py:346
|
||||||
|
msgid "Let other users access to the pool data without logging in."
|
||||||
|
msgstr "Permet à d'autres utilisateurs d'accéder au contenu de la poule sans connexion."
|
||||||
|
|
||||||
|
#: apps/tournament/models.py:380
|
||||||
msgid "pool"
|
msgid "pool"
|
||||||
msgstr "poule"
|
msgstr "poule"
|
||||||
|
|
||||||
#: apps/tournament/models.py:366
|
#: apps/tournament/models.py:381
|
||||||
msgid "pools"
|
msgid "pools"
|
||||||
msgstr "poules"
|
msgstr "poules"
|
||||||
|
|
||||||
#: apps/tournament/models.py:391
|
#: apps/tournament/models.py:406
|
||||||
msgid "Not paid"
|
msgid "Not paid"
|
||||||
msgstr "Non payé"
|
msgstr "Non payé"
|
||||||
|
|
||||||
#: apps/tournament/models.py:392
|
#: apps/tournament/models.py:407
|
||||||
msgid "Credit card"
|
msgid "Credit card"
|
||||||
msgstr "Carte bancaire"
|
msgstr "Carte bancaire"
|
||||||
|
|
||||||
#: apps/tournament/models.py:393
|
#: apps/tournament/models.py:408
|
||||||
msgid "Bank check"
|
msgid "Bank check"
|
||||||
msgstr "Chèque bancaire"
|
msgstr "Chèque bancaire"
|
||||||
|
|
||||||
#: apps/tournament/models.py:394
|
#: apps/tournament/models.py:409
|
||||||
msgid "Bank transfer"
|
msgid "Bank transfer"
|
||||||
msgstr "Virement bancaire"
|
msgstr "Virement bancaire"
|
||||||
|
|
||||||
#: apps/tournament/models.py:395
|
#: apps/tournament/models.py:410
|
||||||
msgid "Cash"
|
msgid "Cash"
|
||||||
msgstr "Espèces"
|
msgstr "Espèces"
|
||||||
|
|
||||||
#: apps/tournament/models.py:399
|
#: apps/tournament/models.py:414
|
||||||
msgid "payment method"
|
msgid "payment method"
|
||||||
msgstr "moyen de paiement"
|
msgstr "moyen de paiement"
|
||||||
|
|
||||||
#: apps/tournament/models.py:413
|
#: apps/tournament/models.py:428
|
||||||
msgid "payment"
|
msgid "payment"
|
||||||
msgstr "paiement"
|
msgstr "paiement"
|
||||||
|
|
||||||
#: apps/tournament/models.py:414
|
#: apps/tournament/models.py:429
|
||||||
msgid "payments"
|
msgid "payments"
|
||||||
msgstr "paiements"
|
msgstr "paiements"
|
||||||
|
|
||||||
#: apps/tournament/models.py:417
|
#: apps/tournament/models.py:432
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Payment of {user}"
|
msgid "Payment of {user}"
|
||||||
msgstr "Paiement de {user}"
|
msgstr "Paiement de {user}"
|
||||||
|
@ -633,71 +647,71 @@ msgstr "Télécharger"
|
||||||
msgid "Problems"
|
msgid "Problems"
|
||||||
msgstr "Problèmes"
|
msgstr "Problèmes"
|
||||||
|
|
||||||
#: apps/tournament/views.py:66
|
#: apps/tournament/views.py:68
|
||||||
msgid "Tournaments list"
|
msgid "Tournaments list"
|
||||||
msgstr "Liste des tournois"
|
msgstr "Liste des tournois"
|
||||||
|
|
||||||
#: apps/tournament/views.py:89
|
#: apps/tournament/views.py:91
|
||||||
msgid "Add tournament"
|
msgid "Add tournament"
|
||||||
msgstr "Ajouter un tournoi"
|
msgstr "Ajouter un tournoi"
|
||||||
|
|
||||||
#: apps/tournament/views.py:106
|
#: apps/tournament/views.py:108
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Tournament of {name}"
|
msgid "Tournament of {name}"
|
||||||
msgstr "Tournoi de {name}"
|
msgstr "Tournoi de {name}"
|
||||||
|
|
||||||
#: apps/tournament/views.py:140
|
#: apps/tournament/views.py:146
|
||||||
msgid "Update tournament"
|
msgid "Update tournament"
|
||||||
msgstr "Modifier le tournoi"
|
msgstr "Modifier le tournoi"
|
||||||
|
|
||||||
#: apps/tournament/views.py:187 apps/tournament/views.py:315
|
#: apps/tournament/views.py:195 apps/tournament/views.py:323
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Solutions for team {team}.zip"
|
msgid "Solutions for team {team}.zip"
|
||||||
msgstr "Solutions pour l'équipe {team}.zip"
|
msgstr "Solutions pour l'équipe {team}.zip"
|
||||||
|
|
||||||
#: apps/tournament/views.py:243
|
#: apps/tournament/views.py:251
|
||||||
msgid "Information about team"
|
msgid "Information about team"
|
||||||
msgstr "Informations sur l'équipe"
|
msgstr "Informations sur l'équipe"
|
||||||
|
|
||||||
#: apps/tournament/views.py:258
|
#: apps/tournament/views.py:266
|
||||||
msgid "Update team"
|
msgid "Update team"
|
||||||
msgstr "Modifier l'équipe"
|
msgstr "Modifier l'équipe"
|
||||||
|
|
||||||
#: apps/tournament/views.py:276
|
#: apps/tournament/views.py:284
|
||||||
msgid "Add organizer"
|
msgid "Add organizer"
|
||||||
msgstr "Ajouter un organisateur"
|
msgstr "Ajouter un organisateur"
|
||||||
|
|
||||||
#: apps/tournament/views.py:299 templates/base.html:108 templates/base.html:126
|
#: apps/tournament/views.py:307 templates/base.html:108 templates/base.html:118
|
||||||
#: templates/tournament/pool_detail.html:31
|
#: templates/base.html:132 templates/tournament/pool_detail.html:31
|
||||||
msgid "Solutions"
|
msgid "Solutions"
|
||||||
msgstr "Solutions"
|
msgstr "Solutions"
|
||||||
|
|
||||||
#: apps/tournament/views.py:339
|
#: apps/tournament/views.py:347
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can't publish your solution anymore. Deadline: {date:%m-%d-%Y %H:%M}."
|
"You can't publish your solution anymore. Deadline: {date:%m-%d-%Y %H:%M}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous ne pouvez plus publier vos solutions. Deadline : {date:%d/%m/%Y %H:%M}."
|
"Vous ne pouvez plus publier vos solutions. Deadline : {date:%d/%m/%Y %H:%M}."
|
||||||
|
|
||||||
#: apps/tournament/views.py:368
|
#: apps/tournament/views.py:376
|
||||||
msgid "All solutions"
|
msgid "All solutions"
|
||||||
msgstr "Toutes les solutions"
|
msgstr "Toutes les solutions"
|
||||||
|
|
||||||
#: apps/tournament/views.py:387
|
#: apps/tournament/views.py:395
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Solutions for tournament {tournament}.zip"
|
msgid "Solutions for tournament {tournament}.zip"
|
||||||
msgstr "Solutions pour le tournoi {tournament}.zip"
|
msgstr "Solutions pour le tournoi {tournament}.zip"
|
||||||
|
|
||||||
#: apps/tournament/views.py:417 templates/base.html:111 templates/base.html:129
|
#: apps/tournament/views.py:432 templates/base.html:111 templates/base.html:121
|
||||||
#: templates/tournament/pool_detail.html:57
|
#: templates/base.html:135 templates/tournament/pool_detail.html:57
|
||||||
msgid "Syntheses"
|
msgid "Syntheses"
|
||||||
msgstr "Synthèses"
|
msgstr "Synthèses"
|
||||||
|
|
||||||
#: apps/tournament/views.py:433
|
#: apps/tournament/views.py:448
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Syntheses for team {team}.zip"
|
msgid "Syntheses for team {team}.zip"
|
||||||
msgstr "Notes de synthèse de l'équipe {team}.zip"
|
msgstr "Notes de synthèse de l'équipe {team}.zip"
|
||||||
|
|
||||||
#: apps/tournament/views.py:458
|
#: apps/tournament/views.py:473
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can't publish your synthesis anymore for the first round. Deadline: "
|
"You can't publish your synthesis anymore for the first round. Deadline: "
|
||||||
"{date:%m-%d-%Y %H:%M}."
|
"{date:%m-%d-%Y %H:%M}."
|
||||||
|
@ -705,7 +719,7 @@ msgstr ""
|
||||||
"Vous ne pouvez plus envoyer vos notes de synthèse pour le premier tour. "
|
"Vous ne pouvez plus envoyer vos notes de synthèse pour le premier tour. "
|
||||||
"Deadline : {date:%d/%m/%Y %h:%M}."
|
"Deadline : {date:%d/%m/%Y %h:%M}."
|
||||||
|
|
||||||
#: apps/tournament/views.py:464
|
#: apps/tournament/views.py:479
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can't publish your synthesis anymore for the second round. Deadline: "
|
"You can't publish your synthesis anymore for the second round. Deadline: "
|
||||||
"{date:%m-%d-%Y %H:%M}."
|
"{date:%m-%d-%Y %H:%M}."
|
||||||
|
@ -713,34 +727,34 @@ msgstr ""
|
||||||
"Vous ne pouvez plus envoyer vos notes de synthèse pour le second tour. "
|
"Vous ne pouvez plus envoyer vos notes de synthèse pour le second tour. "
|
||||||
"Deadline : {date:%d/%m/%Y %h:%M}."
|
"Deadline : {date:%d/%m/%Y %h:%M}."
|
||||||
|
|
||||||
#: apps/tournament/views.py:494
|
#: apps/tournament/views.py:509
|
||||||
msgid "All syntheses"
|
msgid "All syntheses"
|
||||||
msgstr "Toutes les notes de synthèses"
|
msgstr "Toutes les notes de synthèses"
|
||||||
|
|
||||||
#: apps/tournament/views.py:513
|
#: apps/tournament/views.py:528
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Syntheses for tournament {tournament}.zip"
|
msgid "Syntheses for tournament {tournament}.zip"
|
||||||
msgstr "Notes de synthèse pour le tournoi {tournament}.zip"
|
msgstr "Notes de synthèse pour le tournoi {tournament}.zip"
|
||||||
|
|
||||||
#: apps/tournament/views.py:542 templates/base.html:133
|
#: apps/tournament/views.py:571 templates/base.html:125 templates/base.html:138
|
||||||
msgid "Pools"
|
msgid "Pools"
|
||||||
msgstr "Poules"
|
msgstr "Poules"
|
||||||
|
|
||||||
#: apps/tournament/views.py:563
|
#: apps/tournament/views.py:594
|
||||||
msgid "Create pool"
|
msgid "Create pool"
|
||||||
msgstr "Créer une poule"
|
msgstr "Créer une poule"
|
||||||
|
|
||||||
#: apps/tournament/views.py:580
|
#: apps/tournament/views.py:611
|
||||||
msgid "Pool detail"
|
msgid "Pool detail"
|
||||||
msgstr "Détails d'une poule"
|
msgstr "Détails d'une poule"
|
||||||
|
|
||||||
#: apps/tournament/views.py:609
|
#: apps/tournament/views.py:644
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Solutions of a pool for the round {round} of the tournament {tournament}.zip"
|
"Solutions of a pool for the round {round} of the tournament {tournament}.zip"
|
||||||
msgstr "Solutions d'une poule du tour {round} du tournoi {tournament}.zip"
|
msgstr "Solutions d'une poule du tour {round} du tournoi {tournament}.zip"
|
||||||
|
|
||||||
#: apps/tournament/views.py:626
|
#: apps/tournament/views.py:658
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Syntheses of a pool for the round {round} of the tournament {tournament}.zip"
|
"Syntheses of a pool for the round {round} of the tournament {tournament}.zip"
|
||||||
|
@ -826,38 +840,30 @@ msgstr "Rejoindre une équipe"
|
||||||
msgid "My team"
|
msgid "My team"
|
||||||
msgstr "Mon équipe"
|
msgstr "Mon équipe"
|
||||||
|
|
||||||
#: templates/base.html:118
|
#: templates/base.html:144
|
||||||
msgid "Add a tournament"
|
|
||||||
msgstr "Ajouter un tournoi"
|
|
||||||
|
|
||||||
#: templates/base.html:121
|
|
||||||
msgid "Add an organizer"
|
|
||||||
msgstr "Ajouter un organisateur"
|
|
||||||
|
|
||||||
#: templates/base.html:138
|
|
||||||
msgid "Make a gift"
|
msgid "Make a gift"
|
||||||
msgstr "Faire un don"
|
msgstr "Faire un don"
|
||||||
|
|
||||||
#: templates/base.html:142
|
#: templates/base.html:148
|
||||||
msgid "Administration"
|
msgid "Administration"
|
||||||
msgstr "Administration"
|
msgstr "Administration"
|
||||||
|
|
||||||
#: templates/base.html:149
|
#: templates/base.html:155
|
||||||
msgid "Return to admin view"
|
msgid "Return to admin view"
|
||||||
msgstr "Retour à l'interface administrateur"
|
msgstr "Retour à l'interface administrateur"
|
||||||
|
|
||||||
#: templates/base.html:154 templates/registration/login.html:7
|
#: templates/base.html:160 templates/registration/login.html:7
|
||||||
#: templates/registration/login.html:8 templates/registration/login.html:22
|
#: templates/registration/login.html:8 templates/registration/login.html:22
|
||||||
#: templates/registration/password_reset_complete.html:10
|
#: templates/registration/password_reset_complete.html:10
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Connexion"
|
msgstr "Connexion"
|
||||||
|
|
||||||
#: templates/base.html:157 templates/registration/signup.html:5
|
#: templates/base.html:163 templates/registration/signup.html:5
|
||||||
#: templates/registration/signup.html:8 templates/registration/signup.html:14
|
#: templates/registration/signup.html:8 templates/registration/signup.html:14
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "S'inscrire"
|
msgstr "S'inscrire"
|
||||||
|
|
||||||
#: templates/base.html:161
|
#: templates/base.html:167
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Déconnexion"
|
msgstr "Déconnexion"
|
||||||
|
|
||||||
|
@ -867,7 +873,7 @@ msgid "Field filters"
|
||||||
msgstr "Filtres"
|
msgstr "Filtres"
|
||||||
|
|
||||||
#: templates/django_filters/rest_framework/form.html:5
|
#: templates/django_filters/rest_framework/form.html:5
|
||||||
#: templates/member/my_account.html:8 templates/tournament/add_organizer.html:9
|
#: templates/member/my_account.html:9 templates/tournament/add_organizer.html:9
|
||||||
#: templates/tournament/pool_form.html:9
|
#: templates/tournament/pool_form.html:9
|
||||||
#: templates/tournament/solutions_list.html:24
|
#: templates/tournament/solutions_list.html:24
|
||||||
#: templates/tournament/syntheses_list.html:40
|
#: templates/tournament/syntheses_list.html:40
|
||||||
|
@ -876,10 +882,14 @@ msgstr "Filtres"
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr "Envoyer"
|
msgstr "Envoyer"
|
||||||
|
|
||||||
#: templates/member/my_account.html:13
|
#: templates/member/my_account.html:14
|
||||||
msgid "Update my password"
|
msgid "Update my password"
|
||||||
msgstr "Changer mon mot de passe"
|
msgstr "Changer mon mot de passe"
|
||||||
|
|
||||||
|
#: templates/member/profile_list.html:9
|
||||||
|
msgid "Add an organizer"
|
||||||
|
msgstr "Ajouter un organisateur"
|
||||||
|
|
||||||
#: templates/member/tfjmuser_detail.html:12
|
#: templates/member/tfjmuser_detail.html:12
|
||||||
msgid "role"
|
msgid "role"
|
||||||
msgstr "rôle"
|
msgstr "rôle"
|
||||||
|
@ -1045,7 +1055,7 @@ msgid "Solutions will be available here for teams from:"
|
||||||
msgstr "Les solutions seront disponibles ici pour les équipes à partir du :"
|
msgstr "Les solutions seront disponibles ici pour les équipes à partir du :"
|
||||||
|
|
||||||
#: templates/tournament/pool_detail.html:49
|
#: templates/tournament/pool_detail.html:49
|
||||||
#: templates/tournament/pool_detail.html:74
|
#: templates/tournament/pool_detail.html:73
|
||||||
msgid "Download ZIP archive"
|
msgid "Download ZIP archive"
|
||||||
msgstr "Télécharger l'archive ZIP"
|
msgstr "Télécharger l'archive ZIP"
|
||||||
|
|
||||||
|
@ -1058,6 +1068,15 @@ msgstr "Le modèle de note de synthèse est disponible ici :"
|
||||||
msgid "Pool list"
|
msgid "Pool list"
|
||||||
msgstr "Liste des poules"
|
msgstr "Liste des poules"
|
||||||
|
|
||||||
|
#: templates/tournament/pool_detail.html:89
|
||||||
|
msgid ""
|
||||||
|
"Give this link to juries to access this page (warning: should stay "
|
||||||
|
"confidential and only given to juries of this pool):"
|
||||||
|
msgstr ""
|
||||||
|
"Donnez ce lien aux jurys pour leur permettre d'accéder à cette page "
|
||||||
|
"(attention : ce lien doit rester confidentiel et ne doit être donné "
|
||||||
|
"exclusivement qu'à des jurys) :"
|
||||||
|
|
||||||
#: templates/tournament/pool_list.html:10
|
#: templates/tournament/pool_list.html:10
|
||||||
msgid "Add pool"
|
msgid "Add pool"
|
||||||
msgstr "Ajouter une poule"
|
msgstr "Ajouter une poule"
|
||||||
|
@ -1210,10 +1229,14 @@ msgstr "Envoyer un mail à toutes les personnes dans une équipe"
|
||||||
msgid "Send a mail to all people that are in a valid team"
|
msgid "Send a mail to all people that are in a valid team"
|
||||||
msgstr "Envoyer un mail à toutes les personnes dans une équipe validée"
|
msgstr "Envoyer un mail à toutes les personnes dans une équipe validée"
|
||||||
|
|
||||||
#: tfjm/settings.py:146
|
#: templates/tournament/tournament_list.html:15
|
||||||
|
msgid "Add a tournament"
|
||||||
|
msgstr "Ajouter un tournoi"
|
||||||
|
|
||||||
|
#: tfjm/settings.py:147
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr "Anglais"
|
msgstr "Anglais"
|
||||||
|
|
||||||
#: tfjm/settings.py:147
|
#: tfjm/settings.py:148
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr "Français"
|
msgstr "Français"
|
||||||
|
|
|
@ -125,6 +125,20 @@
|
||||||
<a class="nav-link" href="{% url "tournament:pools" %}"><i class="fas fa-swimming-pool"></i> {% trans "Pools" %}</a>
|
<a class="nav-link" href="{% url "tournament:pools" %}"><i class="fas fa-swimming-pool"></i> {% trans "Pools" %}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not user.is_authenticated and request.session.extra_access_token %}
|
||||||
|
{# Juries can access to pool data without logging in. #}
|
||||||
|
<li class="nav-item active">
|
||||||
|
<a class="nav-link" href="{% url "tournament:all_solutions" %}"><i class="fas fa-lightbulb"></i> {% trans "Solutions" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item active">
|
||||||
|
<a class="nav-link" href="{% url "tournament:all_syntheses" %}"><i class="fas fa-feather"></i> {% trans "Syntheses" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item active">
|
||||||
|
<a class="nav-link" href="{% url "tournament:pools" %}"><i class="fas fa-swimming-pool"></i> {% trans "Pools" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
<a class="nav-link" href="https://www.helloasso.com/associations/animath/formulaires/5/widget"><i
|
<a class="nav-link" href="https://www.helloasso.com/associations/animath/formulaires/5/widget"><i
|
||||||
class="fas fa-hand-holding-heart"></i> {% trans "Make a gift" %}</a>
|
class="fas fa-hand-holding-heart"></i> {% trans "Make a gift" %}</a>
|
||||||
|
|
|
@ -61,13 +61,12 @@
|
||||||
{% trans "Templates for syntheses are available here:" %}
|
{% trans "Templates for syntheses are available here:" %}
|
||||||
<a data-turbolinks="false" href="{% static "Fiche synthèse.pdf" %}">PDF</a> -- <a data-turbolinks="false" href="{% static "Fiche synthèse.tex" %}">TEX</a>
|
<a data-turbolinks="false" href="{% static "Fiche synthèse.pdf" %}">PDF</a> -- <a data-turbolinks="false" href="{% static "Fiche synthèse.tex" %}">TEX</a>
|
||||||
</div>
|
</div>
|
||||||
{% if user.organizes %}
|
{% if user.organizes or not user.is_authenticated %}
|
||||||
<ul>
|
<ul>
|
||||||
{% for synthesis in pool.syntheses.all %}
|
{% for synthesis in pool.syntheses.all %}
|
||||||
<li><a data-turbolinks="false" href="{{ synthesis.file.url }}">{{ synthesis }}</a></li>
|
<li><a data-turbolinks="false" href="{{ synthesis.file.url }}">{{ synthesis }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
<div class="card-footer text-center">
|
<div class="card-footer text-center">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
@ -76,10 +75,20 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a class="btn btn-block btn-primary" href="{% url "tournament:pools" %}">{% trans "Pool list" %}</a>
|
<a class="btn btn-block btn-primary" href="{% url "tournament:pools" %}">{% trans "Pool list" %}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if user.organizes or not user.is_authenticated %}
|
||||||
|
<hr>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans "Give this link to juries to access this page (warning: should stay confidential and only given to juries of this pool):" %}<br>
|
||||||
|
<a href="{% url "tournament:pool_detail" pk=pool.pk %}?extra_access_token={{ pool.extra_access_token }}">
|
||||||
|
https://{{ request.get_host }}{% url "tournament:pool_detail" pk=pool.pk %}?extra_access_token={{ pool.extra_access_token }}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -64,6 +64,22 @@ class SessionMiddleware(object):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class ExtraAccessMiddleware(object):
|
||||||
|
"""
|
||||||
|
This middleware allows some non authenticated people to access to pool data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, get_response):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
|
if "extra_access_token" in request.GET:
|
||||||
|
request.session["extra_access_token"] = request.GET["extra_access_token"]
|
||||||
|
else:
|
||||||
|
request.session.setdefault("extra_access_token", "")
|
||||||
|
return self.get_response(request)
|
||||||
|
|
||||||
|
|
||||||
class TurbolinksMiddleware(object):
|
class TurbolinksMiddleware(object):
|
||||||
"""
|
"""
|
||||||
Send the `Turbolinks-Location` header in response to a visit that was redirected,
|
Send the `Turbolinks-Location` header in response to a visit that was redirected,
|
||||||
|
|
|
@ -71,6 +71,7 @@ MIDDLEWARE = [
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.contrib.sites.middleware.CurrentSiteMiddleware',
|
'django.contrib.sites.middleware.CurrentSiteMiddleware',
|
||||||
'tfjm.middlewares.SessionMiddleware',
|
'tfjm.middlewares.SessionMiddleware',
|
||||||
|
'tfjm.middlewares.ExtraAccessMiddleware',
|
||||||
'tfjm.middlewares.TurbolinksMiddleware',
|
'tfjm.middlewares.TurbolinksMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue