mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-06-21 03:18:27 +02:00
Add archive with all notation sheets
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
@ -567,6 +567,10 @@ class Pool(models.Model):
|
||||
"They stay accessible to you. Only averages are given."),
|
||||
)
|
||||
|
||||
@property
|
||||
def short_name(self):
|
||||
return f"{self.get_letter_display()}{self.round}"
|
||||
|
||||
@property
|
||||
def solutions(self):
|
||||
return [passage.defended_solution for passage in self.passages.all()]
|
||||
|
@ -80,7 +80,8 @@
|
||||
{% if user.registration.is_volunteer %}
|
||||
<div class="card-footer text-center">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}">
|
||||
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}">
|
||||
<i class="fas fa-download"></i>
|
||||
{% trans "Download the scale sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
|
||||
</a>
|
||||
{% if pool.passages.count == 5 %}
|
||||
@ -88,18 +89,24 @@
|
||||
{% trans "Room" %} 2
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
|
||||
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
|
||||
<i class="fas fa-download"></i>
|
||||
{% trans "Download the final notation sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
|
||||
</a>
|
||||
{% if pool.passages.count == 5 %}
|
||||
<a class="btn btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}?page=2">
|
||||
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}?page=2">
|
||||
{% trans "Room" %} 2
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_notation_sheets' pool_id=pool.id %}">
|
||||
<i class="fas fa-archive"></i>
|
||||
{% trans "Download all notation sheets" %}
|
||||
</a>
|
||||
</div>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">{% trans "Upload notes from a CSV file" %}</button>
|
||||
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">
|
||||
<i class="fas fa-upload"></i>
|
||||
{% trans "Upload notes from a CSV file" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -82,7 +82,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {%
|
||||
\vspace{15mm}
|
||||
|
||||
\LARGE Nom jur\'e\textperiodcentered{}e :
|
||||
{% if is_jury %}\underline{ {{ user.first_name|safe }} {{ user.last_name|safe }} }{% else %}\underline{\phantom{Phrase suffisamment longue pour le nom}}{% endif %}
|
||||
{% if jury %}\underline{ {{ jury.user.first_name|safe }} {{ jury.user.last_name|safe }} }{% else %}\underline{\phantom{Phrase suffisamment longue pour le nom}}{% endif %}
|
||||
$\qquad$ Signature : \underline{\phantom{Phrase moins longue}}
|
||||
|
||||
\newpage
|
||||
|
@ -195,13 +195,8 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
Archive de tous les barèmes de notes à imprimer triés par poule
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>
|
||||
Archive de tous les tableurs de notes à saisir triés par poule
|
||||
<a href="{% url "participation:tournament_notation_sheets" tournament_id=tournament.id %}">
|
||||
Archive de toutes les feuilles de notes à imprimer triées par poule
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -5,8 +5,8 @@ from django.urls import path
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
|
||||
MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \
|
||||
PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
|
||||
MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, PassageCreateView, \
|
||||
PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
|
||||
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \
|
||||
ScaleNotationSheetTemplateView, SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
|
||||
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
|
||||
@ -43,6 +43,8 @@ urlpatterns = [
|
||||
name="tournament_solutions"),
|
||||
path("tournament/<int:tournament_id>/syntheses/", SolutionsDownloadView.as_view(),
|
||||
name="tournament_syntheses"),
|
||||
path("tournament/<int:tournament_id>/notation/sheets/", NotationSheetsArchiveView.as_view(),
|
||||
name="tournament_notation_sheets"),
|
||||
path("tournament/<int:pk>/publish-notes/<int:round>/", TournamentPublishNotesView.as_view(),
|
||||
name="tournament_publish_notes"),
|
||||
path("pools/create/", PoolCreateView.as_view(), name="pool_create"),
|
||||
@ -52,6 +54,7 @@ urlpatterns = [
|
||||
path("pools/<int:pool_id>/syntheses/", SolutionsDownloadView.as_view(), name="pool_download_syntheses"),
|
||||
path("pools/<int:pk>/notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"),
|
||||
path("pools/<int:pk>/notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
|
||||
path("pools/<int:pool_id>/notation/sheets/", NotationSheetsArchiveView.as_view(), name="pool_notation_sheets"),
|
||||
path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"),
|
||||
path("pools/<int:pk>/jury/", PoolJuryView.as_view(), name="pool_jury"),
|
||||
path("pools/<int:pk>/jury/remove/<int:jury_id>/", PoolRemoveJuryView.as_view(), name="pool_remove_jury"),
|
||||
|
@ -650,7 +650,7 @@ class TournamentExportCSVView(VolunteerMixin, DetailView):
|
||||
if 'all' not in request.GET:
|
||||
participations = participations.filter(valid=True)
|
||||
for participation in participations.order_by('-valid', 'team__trigram').all():
|
||||
for registration in participation.team.participants\
|
||||
for registration in participation.team.participants \
|
||||
.order_by('coachregistration', 'user__last_name').all():
|
||||
writer.writerow({
|
||||
'Tournoi': tournament.name,
|
||||
@ -939,8 +939,8 @@ class PoolJuryView(VolunteerMixin, FormView, DetailView):
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
@ -1022,8 +1022,8 @@ class PoolRemoveJuryView(VolunteerMixin, DetailView):
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
@ -1048,8 +1048,8 @@ class PoolPresideJuryView(VolunteerMixin, DetailView):
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
@ -1076,8 +1076,8 @@ class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
@ -1121,8 +1121,8 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
@ -1313,7 +1313,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
|
||||
for i in range(line_length):
|
||||
table.addElement(TableColumn(stylename=obs_col_style if pool_size == 4
|
||||
and i % passage_width == passage_width - 1 else col_style))
|
||||
and i % passage_width == passage_width - 1 else col_style))
|
||||
|
||||
# Add line for the problems for different passages
|
||||
header_pb = TableRow()
|
||||
@ -1652,6 +1652,17 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView):
|
||||
"""
|
||||
model = Pool
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
if request.user.is_authenticated and \
|
||||
(request.user.registration.is_admin or request.user.registration.is_volunteer
|
||||
and (self.object.tournament in request.user.registration.organized_tournaments.all()
|
||||
or request.user.registration == self.object.jury_president)):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
@ -1661,13 +1672,13 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView):
|
||||
if not page.isnumeric() or page not in ['1', '2']:
|
||||
page = '1'
|
||||
passages = passages.filter(id__in=[passages[0].id, passages[2].id, passages[4].id]
|
||||
if page == '1' else [passages[1].id, passages[3].id])
|
||||
if page == '1' else [passages[1].id, passages[3].id])
|
||||
context['page'] = page
|
||||
|
||||
context['passages'] = passages
|
||||
context['esp'] = passages.count() * '&'
|
||||
context['is_jury'] = self.request.user.registration in self.object.juries.all() \
|
||||
and 'blank' not in self.request.GET
|
||||
if self.request.user.registration in self.object.juries.all() and 'blank' not in self.request.GET:
|
||||
context['jury'] = self.request.user.registration
|
||||
context['tfjm_number'] = timezone.now().year - 2010
|
||||
return context
|
||||
|
||||
@ -1692,6 +1703,95 @@ class FinalNotationSheetTemplateView(NotationSheetTemplateView):
|
||||
template_name = 'participation/tex/finale.tex'
|
||||
|
||||
|
||||
class NotationSheetsArchiveView(VolunteerMixin, DetailView):
|
||||
@property
|
||||
def model(self):
|
||||
return Pool if 'pool_id' in self.kwargs else Tournament
|
||||
|
||||
@property
|
||||
def pk_url_kwarg(self):
|
||||
return 'pool_id' if 'pool_id' in self.kwargs else 'tournament_id'
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_authenticated:
|
||||
return self.handle_no_permission()
|
||||
|
||||
reg = request.user.registration
|
||||
|
||||
if 'pool_id' in kwargs:
|
||||
pool = self.get_object()
|
||||
tournament = pool.tournament
|
||||
if reg.is_admin or reg.is_volunteer \
|
||||
and (tournament in reg.organized_tournaments.all() or reg in pool.juries.all()):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
else:
|
||||
tournament = self.get_object()
|
||||
if reg.is_admin or reg.is_volunteer and tournament in reg.organized_tournaments.all():
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'pool_id' in kwargs:
|
||||
pool = self.get_object()
|
||||
tournament = pool.tournament
|
||||
pools = [pool]
|
||||
filename = _("Notation sheets of pool {pool} of {tournament}.zip") \
|
||||
.format(pool=pool.short_name, tournament=tournament.name)
|
||||
else:
|
||||
tournament = self.get_object()
|
||||
pools = tournament.pools.all()
|
||||
filename = _("Notation sheets of {tournament}.zip").format(tournament=tournament.name)
|
||||
|
||||
output = BytesIO()
|
||||
with ZipFile(output, "w") as zf:
|
||||
for pool in pools:
|
||||
prefix = f"{pool.short_name}/" if len(pools) > 1 else ""
|
||||
for template_name in ['bareme', 'finale']:
|
||||
pages = [1] if pool.participations.count() < 5 else [1, 2]
|
||||
for page in pages:
|
||||
juries = list(pool.juries.all()) + [None]
|
||||
|
||||
for jury in juries:
|
||||
if jury is not None and template_name == "bareme":
|
||||
continue
|
||||
|
||||
context = {'jury': jury, 'page': page, 'pool': pool,
|
||||
'tfjm_number': timezone.now().year - 2010}
|
||||
|
||||
passages = pool.passages.all()
|
||||
if passages.count() == 5:
|
||||
passages = passages.filter(id__in=[passages[0].id, passages[2].id, passages[4].id]
|
||||
if page == '1' else [passages[1].id, passages[3].id])
|
||||
|
||||
context['passages'] = passages
|
||||
context['esp'] = passages.count() * '&'
|
||||
|
||||
tex = render_to_string(f"participation/tex/{template_name}.tex",
|
||||
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()
|
||||
|
||||
sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \
|
||||
else (f"Feuille de notation pour la poule {pool.short_name}"
|
||||
f" - {str(jury) if jury else 'Vierge'}")
|
||||
sheet_name += " - page 2" if page == 2 else ""
|
||||
|
||||
zf.write(os.path.join(temp_dir, "texput.pdf"),
|
||||
f"{prefix}{sheet_name}.pdf")
|
||||
|
||||
response = HttpResponse(content_type="application/zip")
|
||||
response["Content-Disposition"] = f"attachment; filename=\"{filename}\""
|
||||
response.write(output.getvalue())
|
||||
return response
|
||||
|
||||
|
||||
class PassageCreateView(VolunteerMixin, CreateView):
|
||||
model = Passage
|
||||
form_class = PassageForm
|
||||
|
Reference in New Issue
Block a user