mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-06-21 12:38:26 +02:00
Add observer notes
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
@ -323,7 +323,7 @@ class PassageForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Passage
|
||||
fields = ('position', 'solution_number', 'defender', 'opponent', 'reporter', 'defender_penalties',)
|
||||
fields = ('position', 'solution_number', 'defender', 'opponent', 'reporter', 'observer', 'defender_penalties',)
|
||||
|
||||
|
||||
class SynthesisForm(forms.ModelForm):
|
||||
@ -350,4 +350,4 @@ class NoteForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Note
|
||||
fields = ('defender_writing', 'defender_oral', 'opponent_writing',
|
||||
'opponent_oral', 'reporter_writing', 'reporter_oral', )
|
||||
'opponent_oral', 'reporter_writing', 'reporter_oral', 'observer_oral', )
|
||||
|
@ -0,0 +1,45 @@
|
||||
# Generated by Django 4.2 on 2023-04-07 10:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("participation", "0006_alter_passage_options_passage_position_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="note",
|
||||
name="observer_oral",
|
||||
field=models.SmallIntegerField(
|
||||
choices=[
|
||||
(-4, -4),
|
||||
(-3, -3),
|
||||
(-2, -2),
|
||||
(-1, -1),
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(3, 3),
|
||||
(4, 4),
|
||||
],
|
||||
default=0,
|
||||
verbose_name="observer note",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="passage",
|
||||
name="observer",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to="participation.participation",
|
||||
verbose_name="observer",
|
||||
),
|
||||
),
|
||||
]
|
@ -466,6 +466,16 @@ class Passage(models.Model):
|
||||
related_name="+",
|
||||
)
|
||||
|
||||
observer = models.ForeignKey(
|
||||
Participation,
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
default=None,
|
||||
verbose_name=_("observer"),
|
||||
related_name="+",
|
||||
)
|
||||
|
||||
defender_penalties = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("penalties"),
|
||||
default=0,
|
||||
@ -520,9 +530,14 @@ class Passage(models.Model):
|
||||
def average_reporter(self) -> float:
|
||||
return self.average_reporter_writing + self.average_reporter_oral
|
||||
|
||||
@property
|
||||
def average_observer(self) -> float:
|
||||
return self.avg(note.observer_oral for note in self.notes.all())
|
||||
|
||||
def average(self, participation):
|
||||
return self.average_defender if participation == self.defender else self.average_opponent \
|
||||
if participation == self.opponent else self.average_reporter if participation == self.reporter else 0
|
||||
if participation == self.opponent else self.average_reporter if participation == self.reporter \
|
||||
else self.average_observer if participation == self.observer else 0
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse_lazy("participation:passage_detail", args=(self.pk,))
|
||||
@ -537,6 +552,9 @@ class Passage(models.Model):
|
||||
if self.reporter not in self.pool.participations.all():
|
||||
raise ValidationError(_("Team {trigram} is not registered in the pool.")
|
||||
.format(trigram=self.reporter.team.trigram))
|
||||
if self.observer and self.observer not in self.pool.participations.all():
|
||||
raise ValidationError(_("Team {trigram} is not registered in the pool.")
|
||||
.format(trigram=self.observer.team.trigram))
|
||||
return super().clean()
|
||||
|
||||
def __str__(self):
|
||||
@ -716,14 +734,21 @@ class Note(models.Model):
|
||||
default=0,
|
||||
)
|
||||
|
||||
observer_oral = models.SmallIntegerField(
|
||||
verbose_name=_("observer note"),
|
||||
choices=zip(range(-4, 5), range(-4, 5)),
|
||||
default=0,
|
||||
)
|
||||
|
||||
def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int,
|
||||
reporter_writing: int, reporter_oral: int):
|
||||
reporter_writing: int, reporter_oral: int, observer_oral: int = 0):
|
||||
self.defender_writing = defender_writing
|
||||
self.defender_oral = defender_oral
|
||||
self.opponent_writing = opponent_writing
|
||||
self.opponent_oral = opponent_oral
|
||||
self.reporter_writing = reporter_writing
|
||||
self.reporter_oral = reporter_oral
|
||||
self.observer_oral = observer_oral
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse_lazy("participation:passage_detail", args=(self.passage.pk,))
|
||||
@ -733,7 +758,7 @@ class Note(models.Model):
|
||||
|
||||
def __bool__(self):
|
||||
return any((self.defender_writing, self.defender_oral, self.opponent_writing, self.opponent_oral,
|
||||
self.reporter_writing, self.reporter_oral))
|
||||
self.reporter_writing, self.reporter_oral, self.observer_oral))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("note")
|
||||
|
@ -141,4 +141,4 @@ class NoteTable(tables.Table):
|
||||
}
|
||||
model = Note
|
||||
fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
|
||||
'reporter_writing', 'reporter_oral',)
|
||||
'reporter_writing', 'reporter_oral', 'observer_oral',)
|
||||
|
@ -25,6 +25,11 @@
|
||||
<dt class="col-sm-3">{% trans "Reporter:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.reporter.get_absolute_url }}">{{ passage.reporter.team }}</a></dd>
|
||||
|
||||
{% if passage.observer %}
|
||||
<dt class="col-sm-3">{% trans "Observer:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.observer.get_absolute_url }}">{{ passage.observer.team }}</a></dd>
|
||||
{% endif %}
|
||||
|
||||
<dt class="col-sm-3">{% trans "Defended solution:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}</a></dd>
|
||||
|
||||
@ -82,6 +87,11 @@
|
||||
|
||||
<dt class="col-sm-8">{% trans "Average points for the reporter oral:" %}</dt>
|
||||
<dd class="col-sm-4">{{ passage.average_reporter_oral|floatformat }}/10</dd>
|
||||
|
||||
{% if passage.observer %}
|
||||
<dt class="col-sm-8">{% trans "Average points for the observer oral:" %}</dt>
|
||||
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/4</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
@ -95,6 +105,11 @@
|
||||
|
||||
<dt class="col-sm-8">{% trans "Reporter points:" %}</dt>
|
||||
<dd class="col-sm-4">{{ passage.average_reporter|floatformat }}/19</dd>
|
||||
|
||||
{% if passage.observer %}
|
||||
<dt class="col-sm-8">{% trans "Observer points:" %}</dt>
|
||||
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/4</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {%
|
||||
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
|
||||
{% endfor %} & \hline
|
||||
{% if passages.count == 4 %}
|
||||
\multirow{4}{35mm}{\Large Intervention exceptionnelle}& \multicolumn{2}{c|}{\Large {{ passages.last.defender.team.trigram }}}{% for passage in passages.all %}{% if forloop.counter < 4 %} & \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endif %}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
|
||||
\multirow{4}{35mm}{\Large Intervention exceptionnelle}{% for passage in passages.all %} & \multicolumn{2}{c|}{\Large {{ passage.observer.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
|
||||
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
|
||||
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
|
||||
& \multicolumn{2}{c|}{\phantom{asd asd} \phantom{asd asd}}
|
||||
|
@ -920,6 +920,9 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
|
||||
context["notes"] = NoteTable([note for note in self.object.notes.all() if note])
|
||||
elif self.request.user.registration.is_admin:
|
||||
context["notes"] = NoteTable([note for note in self.object.notes.all() if note])
|
||||
if 'notes' in context and not self.object.observer:
|
||||
# Only display the observer column for 4-teams pools
|
||||
context['notes']._sequence.pop()
|
||||
return context
|
||||
|
||||
|
||||
@ -1003,3 +1006,10 @@ class NoteUpdateView(VolunteerMixin, UpdateView):
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
return self.handle_no_permission()
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
if not self.object.passage.observer:
|
||||
# Set the note of the observer only for 4-teams pools
|
||||
del form.fields['observer_oral']
|
||||
return form
|
||||
|
Reference in New Issue
Block a user