1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-24 08:21:20 +00:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Emmy D'Anello
10a42d3633
Only harmonize valid participations
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 22:12:54 +02:00
Emmy D'Anello
bb579d640c
Add buttons to hide notes from public if needed
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 22:11:01 +02:00
Emmy D'Anello
d7b4233282
Rapporteure -> Rapportrice
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 21:47:14 +02:00
Emmy D'Anello
9092cf1846
Improve edit buttons
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 21:36:09 +02:00
Emmy D'Anello
37b86d4ea0
Better download link to the ODS file
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 21:23:57 +02:00
Emmy D'Anello
40988348d3
Upload notes to Google Sheets after uploading a CSV file
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 20:59:00 +02:00
Emmy D'Anello
1cbf95e6e1
Display at least our notes in the notes table
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-03-31 20:56:49 +02:00
10 changed files with 581 additions and 412 deletions

File diff suppressed because it is too large Load Diff

View File

@ -128,7 +128,7 @@ class ValidateParticipationForm(forms.Form):
class TournamentForm(forms.ModelForm): class TournamentForm(forms.ModelForm):
class Meta: class Meta:
model = Tournament model = Tournament
fields = '__all__' exclude = ('notes_sheet_id', )
widgets = { widgets = {
'date_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), 'date_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
'date_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), 'date_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),

View File

@ -928,7 +928,7 @@ class Pool(models.Model):
header = [ header = [
sum(([f"Problème {passage.solution_number}"] + (passage_width - 1) * [""] sum(([f"Problème {passage.solution_number}"] + (passage_width - 1) * [""]
for passage in passages), start=["Problème", ""]), for passage in passages), start=["Problème", ""]),
sum((["Défenseur⋅se", "", "Opposant⋅e", "", "Rapporteur⋅e", ""] sum((["Défenseur⋅se", "", "Opposant⋅e", "", "Rapporteur⋅rice", ""]
+ (["Observateur⋅rice"] if pool_size == 4 else []) + (["Observateur⋅rice"] if pool_size == 4 else [])
for _passage in passages), start=["Rôle", ""]), for _passage in passages), start=["Rôle", ""]),
sum((["Écrit (/20)", "Oral (/20)", "Écrit (/10)", "Oral (/10)", "Écrit (/10)", "Oral (/10)"] sum((["Écrit (/20)", "Oral (/20)", "Écrit (/10)", "Oral (/10)", "Écrit (/10)", "Oral (/10)"]

View File

@ -6,7 +6,16 @@
{% trans "any" as any %} {% trans "any" as any %}
<div class="card bg-body shadow"> <div class="card bg-body shadow">
<div class="card-header text-center"> <div class="card-header text-center">
<h4>{{ passage }}</h4> <h4>
{{ passage }}
{% if user.registration.is_admin or user.registration in passage.pool.tournament.organizers.all %}
<button class="btn btn-sm btn-secondary"
data-bs-toggle="modal" data-bs-target="#updatePassageModal">
<i class="fas fa-edit"></i>
{% trans "Update" %}
</button>
{% endif %}
</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<dl class="row"> <dl class="row">
@ -51,7 +60,6 @@
{% if my_note is not None %} {% if my_note is not None %}
<button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#{{ my_note.modal_name }}Modal">{% trans "Update notes" %}</button> <button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#{{ my_note.modal_name }}Modal">{% trans "Update notes" %}</button>
{% endif %} {% endif %}
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePassageModal">{% trans "Update" %}</button>
</div> </div>
{% elif user.registration.participates %} {% elif user.registration.participates %}
<div class="card-footer text-center"> <div class="card-footer text-center">

View File

@ -5,7 +5,15 @@
{% block content %} {% block content %}
<div class="card bg-body shadow"> <div class="card bg-body shadow">
<div class="card-header text-center"> <div class="card-header text-center">
<h4>{{ pool }}</h4> <h4>
{{ pool }}
{% if user.registration.is_admin or user.registration in pool.tournament.organizers.all %}
<button class="btn btn-sm btn-secondary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">
<i class="fas fa-edit"></i>
{% trans "Update" %}
</button>
{% endif %}
</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<dl class="row"> <dl class="row">
@ -62,35 +70,15 @@
</a> </a>
</dd> </dd>
{% if pool.bbb_url %}
<dt class="col-sm-3">{% trans "BigBlueButton link:" %}</dt> <dt class="col-sm-3">{% trans "BigBlueButton link:" %}</dt>
<dd class="col-sm-9">{{ pool.bbb_url|urlize }}</dd> <dd class="col-sm-9">{{ pool.bbb_url|urlize }}</dd>
{% endif %}
{% if user.registration.is_admin or user.registration.is_volunteer %} {% if user.registration.is_admin or user.registration.is_volunteer %}
{% if user.registration.is_admin or user.registration in pool.tournament.organizers.all or user.registration == pool.jury_president %} {% if user.registration.is_admin or user.registration in pool.tournament.organizers.all or user.registration == pool.jury_president %}
<dt class="col-sm-3">{% trans "Notation sheet:" %}</dt> <dt class="col-sm-3">{% trans "Notation sheets:" %}</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
<a class="btn btn-success" href="https://docs.google.com/spreadsheets/d/{{ pool.tournament.notes_sheet_id }}/edit">
<i class="fas fa-table"></i>
{% trans "Go to the Google Sheets page of the pool" %}
</a>
</dd>
{% endif %}
{% endif %}
</dl>
<div class="card bg-body shadow">
<div class="card-header text-center">
<h5>{% trans "Ranking" %}</h5>
</div>
<div class="card-body">
<ul>
{% for participation, note in notes %}
<li><strong>{{ participation.team }} :</strong> {{ note|floatformat }}</li>
{% endfor %}
</ul>
</div>
{% if user.registration.is_volunteer %}
<div class="card-footer text-center">
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-sm 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> <i class="fas fa-download"></i>
@ -115,19 +103,48 @@
{% trans "Download all notation sheets" %} {% trans "Download all notation sheets" %}
</a> </a>
</div> </div>
</dd>
<dt class="col-sm-3">{% trans "Google Sheets Spreadsheet:" %}</dt>
<dd class="col-sm-9">
<a class="btn btn-sm btn-success" href="https://docs.google.com/spreadsheets/d/{{ pool.tournament.notes_sheet_id }}/edit">
<i class="fas fa-table"></i>
{% trans "Go to the Google Sheets page of the pool" %}
</a>
</dd>
{% endif %}
{% endif %}
</dl>
<div class="card bg-body shadow">
<div class="card-header text-center">
<h5>{% trans "Ranking" %}</h5>
</div>
<div class="card-body">
<ul>
{% for participation, note in notes %}
<li><strong>{{ participation.team }} :</strong> {{ note|floatformat }}</li>
{% endfor %}
</ul>
</div>
{% if user.registration.is_admin or user.registration.is_volunteer %}
{% if user.registration.is_admin or user.registration in pool.tournament.organizers.all or user.registration == pool.jury_president %}
<div class="card-footer text-center">
<div class="btn btn-group">
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal"> <button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#uploadNotesModal">
<i class="fas fa-upload"></i> <i class="fas fa-upload"></i>
{% trans "Upload notes from a CSV file" %} {% trans "Upload notes from a CSV file" %}
</button> </button>
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_notes_template' pk=pool.pk %}">
<i class="fas fa-download"></i>
{% trans "Download notation spreadsheet" %}
</a>
</div> </div>
</div>
{% endif %}
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% if user.registration.is_volunteer %}
<div class="card-footer text-center">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">{% trans "Update" %}</button>
</div>
{% endif %}
</div> </div>
<hr> <hr>

View File

@ -61,7 +61,10 @@
{% if user.registration.is_admin or user.registration in tournament.organizers.all %} {% if user.registration.is_admin or user.registration in tournament.organizers.all %}
<div class="card-footer text-center"> <div class="card-footer text-center">
<a href="{% url "participation:tournament_update" pk=tournament.pk %}"><button class="btn btn-secondary">{% trans "Edit tournament" %}</button></a> <a class="btn btn-secondary" href="{% url "participation:tournament_update" pk=tournament.pk %}">
<i class="fas fa-edit"></i>
{% trans "Edit tournament" %}
</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
@ -106,22 +109,6 @@
</div> </div>
{% if user.registration.is_admin or user.registration in tournament.organizers.all %} {% if user.registration.is_admin or user.registration in tournament.organizers.all %}
<div class="card-footer text-center"> <div class="card-footer text-center">
{% if not available_notes_1 or not available_notes_2 %}
<div class="btn-group">
{% if not available_notes_1 %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=1 %}" class="btn btn-info">
<i class="fas fa-upload"></i>
{% trans "Publish notes for first round" %}
</a>
{% endif %}
{% if not available_notes_2 %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=2 %}" class="btn btn-info">
<i class="fas fa-upload"></i>
{% trans "Publish notes for second round" %}
</a>
{% endif %}
</div>
{% endif %}
<div class="btn-group"> <div class="btn-group">
<a href="{% url 'participation:tournament_harmonize' pk=tournament.pk round=1 %}" class="btn btn-secondary"> <a href="{% url 'participation:tournament_harmonize' pk=tournament.pk round=1 %}" class="btn btn-secondary">
<i class="fas fa-ranking-star"></i> <i class="fas fa-ranking-star"></i>
@ -133,6 +120,32 @@
</a> </a>
</div> </div>
</div> </div>
<div class="card-footer text-center">
<div class="btn-group">
{% if not available_notes_1 %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=1 %}" class="btn btn-sm btn-info">
<i class="fas fa-eye"></i>
{% trans "Publish notes for first round" %}
</a>
{% else %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=1 %}?hide" class="btn btn-sm btn-danger">
<i class="fas fa-eye-slash"></i>
{% trans "Unpublish notes for first round" %}
</a>
{% endif %}
{% if not available_notes_2 %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=2 %}" class="btn btn-sm btn-info">
<i class="fas fa-eye"></i>
{% trans "Publish notes for second round" %}
</a>
{% else %}
<a href="{% url 'participation:tournament_publish_notes' pk=tournament.pk round=2 %}?hide" class="btn btn-sm btn-danger">
<i class="fas fa-eye-slash"></i>
{% trans "Unpublish notes for second round" %}
</a>
{% endif %}
</div>
</div>
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}

View File

@ -6,6 +6,14 @@
{% block content %} {% block content %}
<form method="post" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<div id="form-content"> <div id="form-content">
<div class="alert alert-warning">
{% url 'participation:pool_jury' pk=pool.jury as jury_url %}
{% blocktrans trimmed with jury_url=jury_url %}
Remember to export your spreadsheet as a CSV file before uploading it here.
Rows that are full of zeros are ignored.
Unknown juries are not considered.
{% endblocktrans %}
</div>
<div class="alert alert-info"> <div class="alert alert-info">
<a class="alert-link" href="{% url "participation:pool_notes_template" pk=pool.pk %}"> <a class="alert-link" href="{% url "participation:pool_notes_template" pk=pool.pk %}">
{% trans "Download empty notation sheet" %} {% trans "Download empty notation sheet" %}

View File

@ -703,8 +703,11 @@ class TournamentPublishNotesView(VolunteerMixin, SingleObjectMixin, RedirectView
raise Http404 raise Http404
tournament = Tournament.objects.get(pk=kwargs["pk"]) tournament = Tournament.objects.get(pk=kwargs["pk"])
tournament.pools.filter(round=kwargs["round"]).update(results_available=True) tournament.pools.filter(round=kwargs["round"]).update(results_available='hide' not in request.GET)
if 'hide' not in request.GET:
messages.success(request, _("Notes published!")) messages.success(request, _("Notes published!"))
else:
messages.success(request, _("Notes hidden!"))
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_redirect_url(self, *args, **kwargs): def get_redirect_url(self, *args, **kwargs):
@ -739,7 +742,7 @@ class TournamentHarmonizeView(VolunteerMixin, DetailView):
.format(tournament=tournament, round=context["round"]) .format(tournament=tournament, round=context["round"])
notes = dict() notes = dict()
for participation in self.object.participations.all(): for participation in self.object.participations.filter(valid=True).all():
note = sum(pool.average(participation) for pool in context['pools']) note = sum(pool.average(participation) for pool in context['pools'])
tweak = sum(tweak.diff for tweak in participation.tweaks.filter(pool__in=context['pools']).all()) tweak = sum(tweak.diff for tweak in participation.tweaks.filter(pool__in=context['pools']).all())
notes[participation] = {'note': note, 'tweak': tweak} notes[participation] = {'note': note, 'tweak': tweak}
@ -759,13 +762,14 @@ class TournamentHarmonizeNoteView(VolunteerMixin, DetailView):
if not reg.is_admin and (not reg.is_volunteer or tournament not in reg.organized_tournaments.all()): if not reg.is_admin and (not reg.is_volunteer or tournament not in reg.organized_tournaments.all()):
return self.handle_no_permission() return self.handle_no_permission()
if self.kwargs['round'] not in (1, 2) or self.kwargs['action'] not in ('add', 'remove') \ if self.kwargs['round'] not in (1, 2) or self.kwargs['action'] not in ('add', 'remove') \
or self.kwargs['trigram'] not in [p.team.trigram for p in tournament.participations.all()]: or self.kwargs['trigram'] not in [p.team.trigram
for p in tournament.participations.filter(valid=True).all()]:
raise Http404 raise Http404
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
tournament = self.get_object() tournament = self.get_object()
participation = tournament.participations.get(team__trigram=kwargs['trigram']) participation = tournament.participations.filter(valid=True).get(team__trigram=kwargs['trigram'])
pool = tournament.pools.get(round=kwargs['round'], participations=participation) pool = tournament.pools.get(round=kwargs['round'], participations=participation)
tweak_qs = Tweak.objects.filter(participation=participation, pool=pool) tweak_qs = Tweak.objects.filter(participation=participation, pool=pool)
old_diff = tweak_qs.first().diff if tweak_qs.exists() else 0 old_diff = tweak_qs.first().diff if tweak_qs.exists() else 0
@ -1177,6 +1181,9 @@ class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
note.set_all(*list(map(int, passage_notes))) note.set_all(*list(map(int, passage_notes)))
note.save() note.save()
if os.getenv('GOOGLE_PRIVATE_KEY_ID', None):
pool.update_notes_spreadsheet()
messages.success(self.request, _("Notes were successfully uploaded.")) messages.success(self.request, _("Notes were successfully uploaded."))
return super().form_valid(form) return super().form_valid(form)
@ -1428,7 +1435,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
reporter_tc = TableCell(valuetype="string", reporter_tc = TableCell(valuetype="string",
stylename=title_style_right if pool_size != 4 else title_style) stylename=title_style_right if pool_size != 4 else title_style)
reporter_tc.addElement(P(text="Rapporteur⋅e")) reporter_tc.addElement(P(text="Rapporteur⋅rice"))
reporter_tc.setAttribute('numbercolumnsspanned', "2") reporter_tc.setAttribute('numbercolumnsspanned', "2")
header_role.addElement(reporter_tc) header_role.addElement(reporter_tc)
header_role.addElement(CoveredTableCell()) header_role.addElement(CoveredTableCell())
@ -1892,9 +1899,9 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
if reg.is_volunteer: if reg.is_volunteer:
notes = self.object.notes.all() notes = self.object.notes.all()
if not reg.is_admin \ if not reg.is_admin \
or (reg != self.object.pool.jury_president and (reg != self.object.pool.jury_president
and reg not in self.object.pool.tournament.organizers.all()): or reg not in self.object.pool.tournament.organizers.all()):
notes = [note for note in notes if note.has_any_note()] notes = [note for note in notes if note.has_any_note() or note.jury == reg]
context["notes"] = NoteTable(notes) context["notes"] = NoteTable(notes)
# Only display the observer column for 4-teams pools # Only display the observer column for 4-teams pools

Binary file not shown.

View File

@ -53,7 +53,7 @@ Problème \underline{~~~~} défendu par l'équipe \underline{~~~~~~~~~~~~~~~~~~~
\medskip \medskip
Synthèse par l'équipe \underline{~~~~~~~~~~~~~~~~~~~~~~~~~~~~} dans le rôle de : ~ $\square$ Opposante ~ $\square$ Rapporteure Synthèse par l'équipe \underline{~~~~~~~~~~~~~~~~~~~~~~~~~~~~} dans le rôle de : ~ $\square$ Opposante ~ $\square$ Rapportrice
\section*{\'Evaluation question par question de la solution} \section*{\'Evaluation question par question de la solution}