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:
@ -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"))
|
||||
|
@ -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',
|
||||
)
|
||||
|
27
participation/migrations/0009_pool_jury_president.py
Normal file
27
participation/migrations/0009_pool_jury_president.py
Normal 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",
|
||||
),
|
||||
),
|
||||
]
|
@ -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,
|
||||
|
@ -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 %}
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user