1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-06-23 07:16:36 +02:00

Add button to update notes

Add jury president field for pools

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello
2024-03-24 15:36:51 +01:00
parent 6fa3a08a72
commit 0b9079b431
8 changed files with 220 additions and 78 deletions

View File

@ -43,7 +43,7 @@ class SynthesisInline(admin.TabularInline):
class PoolInline(admin.TabularInline):
model = Pool
extra = 0
autocomplete_fields = ('tournament', 'participations', 'juries',)
autocomplete_fields = ('tournament', 'participations', 'jury_president', 'juries',)
show_change_link = True
@ -100,10 +100,10 @@ class ParticipationAdmin(admin.ModelAdmin):
@admin.register(Pool)
class PoolAdmin(admin.ModelAdmin):
list_display = ('__str__', 'tournament', 'round', 'letter', 'teams',)
list_display = ('__str__', 'tournament', 'round', 'letter', 'teams', 'jury_president',)
list_filter = ('tournament', 'round', 'letter',)
search_fields = ('participations__team__name', 'participations__team__trigram',)
autocomplete_fields = ('tournament', 'participations', 'juries',)
autocomplete_fields = ('tournament', 'participations', 'jury_president', 'juries',)
inlines = (PassageInline, TweakInline,)
@admin.display(description=_("teams"))

View File

@ -218,19 +218,19 @@ class AddJuryForm(forms.ModelForm):
Div(
Div(
Field('email', autofocus="autofocus", list="juries-email"),
css_class='col-md-5',
css_class='col-md-5 px-1',
),
Div(
Field('first_name', list="juries-first-name"),
css_class='col-md-3',
css_class='col-md-3 px-1',
),
Div(
Field('last_name', list="juries-last-name"),
css_class='col-md-3',
css_class='col-md-3 px-1',
),
Div(
Submit('submit', _("Add")),
css_class='col-md-1 py-md-4',
css_class='col-md-1 py-md-4 px-1',
),
css_class='row',
)

View File

@ -0,0 +1,27 @@
# Generated by Django 5.0.2 on 2024-03-24 14:31
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("participation", "0008_alter_participation_options"),
("registration", "0012_payment_token_alter_payment_type"),
]
operations = [
migrations.AddField(
model_name="pool",
name="jury_president",
field=models.ForeignKey(
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="pools_presided",
to="registration.volunteerregistration",
verbose_name="president of the jury",
),
),
]

View File

@ -8,7 +8,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
from django.db import models
from django.db.models import Index
from django.db.models import F, Index, Q
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.crypto import get_random_string
@ -543,6 +543,15 @@ class Pool(models.Model):
verbose_name=_("juries"),
)
jury_president = models.ForeignKey(
VolunteerRegistration,
on_delete=models.SET_NULL,
null=True,
default=None,
related_name="pools_presided",
verbose_name=_("president of the jury"),
)
bbb_url = models.CharField(
max_length=255,
blank=True,
@ -573,6 +582,11 @@ class Pool(models.Model):
def get_absolute_url(self):
return reverse_lazy("participation:pool_detail", args=(self.pk,))
def validate_constraints(self, exclude=None):
if self.jury_president not in self.juries.all():
raise ValidationError({'jury_president': _("The president of the jury must be part of the jury.")})
return super().validate_constraints()
def __str__(self):
return _("Pool of day {round} for tournament {tournament} with teams {teams}")\
.format(round=self.round,

View File

@ -4,23 +4,53 @@
{% load i18n %}
{% block content %}
<div class="alert alert-info">
<p>
{% blocktrans trimmed %}
On this page, you can manage the juries of the pool. You can add a new jury by entering the email address
of the jury. If the jury is not registered, the account will be created automatically. If the jury already
exists, its account will be autocompleted and directly linked to the pool.
{% endblocktrans %}
</p>
<p>
{% blocktrans trimmed %}
On this page, you can also define the president of the jury, who will have the right to see all solutions
and if necessary define the notes of other jury members.
{% endblocktrans %}
</p>
</div>
<hr>
{% for jury in pool.juries.all %}
<div class="row my-3">
<div class="col-md-5">
<div class="row my-3 px-0">
<div class="col-md-5 px-1">
<input type="email" class="form-control" value="{{ jury.user.email }}" disabled>
</div>
<div class="col-md-3">
<div class="col-md-3 px-1">
<input type="text" class="form-control" value="{{ jury.user.first_name }}" disabled>
</div>
<div class="col-md-3">
<div class="col-md-3 px-1">
<input type="text" class="form-control" value="{{ jury.user.last_name }}" disabled>
</div>
<div class="col-md-1">
<a href="{% url 'participation:pool_remove_jury' pk=pool.pk jury_id=jury.id %}" class="btn btn-danger">
Retirer
</a>
<div class="col-md-1 px-1">
<div class="btn-group-vertical btn-group-sm">
{% if jury == pool.jury_president %}
<button class="btn btn-success">
<i class="fas fa-crown"></i> {% trans "PoJ" %}
</button>
{% else %}
<a href="{% url 'participation:pool_preside' pk=pool.pk jury_id=jury.id %}"
class="btn btn-warning">
<i class="fas fa-crown"></i> {% trans "Preside" %}
</a>
{% endif %}
<a href="{% url 'participation:pool_remove_jury' pk=pool.pk jury_id=jury.id %}"
class="btn btn-danger">
<i class="fas fa-trash"></i> {% trans "Remove" %}
</a>
</div>
</div>
</div>
{% endfor %}

View File

@ -7,10 +7,10 @@ from django.views.generic import TemplateView
from .views import CreateTeamView, FinalNotationSheetTemplateView, JoinTeamView, MyParticipationDetailView, \
MyTeamDetailView, NoteUpdateView, ParticipationDetailView, PassageCreateView, PassageDetailView, \
PassageUpdateView, PoolCreateView, PoolDetailView, PoolDownloadView, PoolJuryView, PoolNotesTemplateView, \
PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, ScaleNotationSheetTemplateView, \
SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, \
TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, \
TournamentExportCSVView, TournamentListView, TournamentPaymentsView, TournamentUpdateView
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, \
ScaleNotationSheetTemplateView, SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, TeamDetailView, \
TeamLeaveView, TeamListView, TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, \
TournamentDetailView, TournamentExportCSVView, TournamentListView, TournamentPaymentsView, TournamentUpdateView
app_name = "participation"
@ -45,6 +45,7 @@ urlpatterns = [
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"),

View File

@ -885,6 +885,29 @@ class PoolRemoveJuryView(VolunteerMixin, DetailView):
return redirect(reverse_lazy('participation:pool_jury', args=(pool.pk,)))
class PoolPresideJuryView(VolunteerMixin, DetailView):
model = Pool
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():
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
def get(self, request, *args, **kwargs):
pool = self.get_object()
if not pool.juries.filter(pk=kwargs['jury_id']).exists():
raise Http404
jury = pool.juries.get(pk=kwargs['jury_id'])
pool.jury_president = jury
pool.save()
messages.success(request, _("The jury {name} has been successfully promoted president!")
.format(name=f"{jury.user.first_name} {jury.user.last_name}"))
return redirect(reverse_lazy('participation:pool_jury', args=(pool.pk,)))
class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
model = Pool
form_class = UploadNotesForm