1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-24 13:41:19 +00:00

Compare commits

..

No commits in common. "630633bab48f3094bf4cd9618a203ce51089e850" and "29b01ebb132b1a30d6892363f394dd97495e4bd2" have entirely different histories.

6 changed files with 99 additions and 41 deletions

View File

@ -399,8 +399,6 @@ class Pool(models.Model):
passage.observer = tds[line[3]].participation
await passage.asave()
await sync_to_async(self.associated_pool.update_spreadsheet)()
return self.associated_pool
def __str__(self):

View File

@ -192,6 +192,24 @@ class PoolForm(forms.ModelForm):
}
class PoolTeamsForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["participations"].queryset = self.instance.tournament.participations.all()
class Meta:
model = Pool
fields = ('participations',)
widgets = {
"participations": forms.SelectMultiple(attrs={
'class': 'selectpicker',
'data-live-search': 'true',
'data-live-search-normalize': 'true',
'data-width': 'fit',
}),
}
class AddJuryForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View File

@ -453,23 +453,15 @@ class Tournament(models.Model):
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
tweak1 = tweak1_qs.get() if tweak1_qs.exists() else None
line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + passage1.position}; 0)")
line.append(tweak1.diff if tweak1 else 0)
if self.pools.filter(round=2, participations=participation).exists():
pool2 = self.pools.get(round=2, participations=participation)
passage2 = pool2.passages.get(defender=participation)
tweak2_qs = Tweak.objects.filter(pool=pool2, participation=participation)
tweak2 = tweak2_qs.get() if tweak2_qs.exists() else None
line.append(
f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + passage2.position}; 0)")
line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + passage1.position}; 0)")
line.append(tweak1.diff if tweak1 else 0)
line.append(f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + passage2.position}; 0)")
line.append(tweak2.diff if tweak2 else 0)
else:
# User has no second pool yet
line.append(0)
line.append(0)
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}")
line.append(f"=RANG($F{i + 2}; $F$2:$F${participations.count() + 1})")
@ -617,19 +609,16 @@ class Tournament(models.Model):
trigram = line[0][-4:-1]
participation = self.participations.get(team__trigram=trigram)
pool1 = self.pools.get(round=1, participations=participation)
pool2 = self.pools.get(round=2, participations=participation)
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
tweak1_nb = int(line[2])
tweak2_qs = Tweak.objects.filter(pool=pool2, participation=participation)
tweak1_nb, tweak2_nb = int(line[2]), int(line[4])
if not tweak1_nb:
tweak1_qs.delete()
else:
tweak1_qs.update_or_create(defaults={'diff': tweak1_nb},
create_defaults={'diff': tweak1_nb, 'pool': pool1,
'participation': participation})
if self.pools.filter(round=2, participations=participation).exists():
pool2 = self.pools.get(round=2, participations=participation)
tweak2_qs = Tweak.objects.filter(pool=pool2, participation=participation)
tweak2_nb = int(line[4])
if not tweak2_nb:
tweak2_qs.delete()
else:
@ -1310,6 +1299,11 @@ class Pool(models.Model):
note.set_all(*note_line)
note.save()
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if os.getenv('GOOGLE_PRIVATE_KEY_ID', None): # Google Sheets support is enabled
self.update_juries_lines_spreadsheet()
super().save(force_insert, force_update, using, update_fields)
def __str__(self):
return _("Pool of day {round} for tournament {tournament} with teams {teams}")\
.format(round=self.round,

View File

@ -125,7 +125,9 @@
</div>
{% if user.registration.is_volunteer %}
<div class="card-footer text-center">
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addPassageModal">{% trans "Add passage" %}</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updatePoolModal">{% trans "Update" %}</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updateTeamsModal">{% trans "Update teams" %}</button>
</div>
{% endif %}
</div>
@ -136,11 +138,21 @@
{% render_table passages %}
{% trans "Add passage" as modal_title %}
{% trans "Add" as modal_button %}
{% url "participation:passage_create" pk=pool.pk as modal_action %}
{% include "base_modal.html" with modal_id="addPassage" modal_button_type="success" %}
{% trans "Update pool" as modal_title %}
{% trans "Update" as modal_button %}
{% url "participation:pool_update" pk=pool.pk as modal_action %}
{% include "base_modal.html" with modal_id="updatePool" %}
{% trans "Update teams" as modal_title %}
{% trans "Update" as modal_button %}
{% url "participation:pool_update_teams" pk=pool.pk as modal_action %}
{% include "base_modal.html" with modal_id="updateTeams" %}
{% trans "Upload notes" as modal_title %}
{% trans "Upload" as modal_button %}
{% url "participation:pool_upload_notes" pk=pool.pk as modal_action %}
@ -151,6 +163,8 @@
<script>
document.addEventListener('DOMContentLoaded', () => {
initModal("updatePool", "{% url "participation:pool_update" pk=pool.pk %}")
initModal("updateTeams", "{% url "participation:pool_update_teams" pk=pool.pk %}")
initModal("addPassage", "{% url "participation:passage_create" pk=pool.pk %}")
initModal("uploadNotes", "{% url "participation:pool_upload_notes" pk=pool.pk %}")
})
</script>

View File

@ -5,9 +5,9 @@ from django.urls import path
from django.views.generic import TemplateView
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, \
MyTeamDetailView, NotationSheetsArchiveView, NoteUpdateView, ParticipationDetailView, PassageCreateView, \
PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateView, PoolUploadNotesView, \
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \
ScaleNotationSheetTemplateView, SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
@ -60,11 +60,13 @@ urlpatterns = [
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"),
path("pools/<int:pk>/jury/preside/<int:jury_id>/", PoolPresideJuryView.as_view(), name="pool_preside"),
path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"),
path("pools/<int:pk>/upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"),
path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"),
path("pools/passages/<int:pk>/", PassageDetailView.as_view(), name="passage_detail"),
path("pools/passages/<int:pk>/update/", PassageUpdateView.as_view(), name="passage_update"),
path("pools/passages/<int:pk>/solution/", SynthesisUploadView.as_view(), name="upload_synthesis"),

View File

@ -40,7 +40,7 @@ from tfjm.lists import get_sympa_client
from tfjm.views import AdminMixin, VolunteerMixin
from .forms import AddJuryForm, JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, \
PoolForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \
PoolForm, PoolTeamsForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \
UploadNotesForm, ValidateParticipationForm
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
from .tables import NoteTable, ParticipationTable, PassageTable, PoolTable, TeamTable, TournamentTable
@ -880,12 +880,19 @@ class PoolUpdateView(VolunteerMixin, UpdateView):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def form_valid(self, form):
ret = super().form_valid(form)
# Update Google Sheets juries lines
if os.getenv('GOOGLE_PRIVATE_KEY_ID', None):
self.object.update_juries_lines_spreadsheet()
return ret
class PoolUpdateTeamsView(VolunteerMixin, UpdateView):
model = Pool
form_class = PoolTeamsForm
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
if request.user.registration.is_admin or request.user.registration.is_volunteer \
and (self.get_object().tournament in request.user.registration.organized_tournaments.all()
or request.user.registration in self.get_object().juries.all()):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
class SolutionsDownloadView(VolunteerMixin, View):
@ -1068,10 +1075,6 @@ class PoolJuryView(VolunteerMixin, FormView, DetailView):
self.object.juries.add(reg)
self.object.save()
# Update Google Sheets juries lines
if os.getenv('GOOGLE_PRIVATE_KEY_ID', None):
self.object.update_juries_lines_spreadsheet()
# Add notification
messages.success(self.request, _("The jury {name} has been successfully added!")
.format(name=f"{user.first_name} {user.last_name}"))
@ -1867,6 +1870,35 @@ class NotationSheetsArchiveView(VolunteerMixin, DetailView):
return response
class PassageCreateView(VolunteerMixin, CreateView):
model = Passage
form_class = PassageForm
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
qs = Pool.objects.filter(pk=self.kwargs["pk"])
if not qs.exists():
raise Http404
self.pool = qs.get()
if request.user.registration.is_admin or request.user.registration.is_volunteer \
and (self.pool.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration in self.pool.juries.all()):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.instance.pool = self.pool
form.fields["defender"].queryset = self.pool.participations.all()
form.fields["opponent"].queryset = self.pool.participations.all()
form.fields["reporter"].queryset = self.pool.participations.all()
return form
class PassageDetailView(LoginRequiredMixin, DetailView):
model = Passage