diff --git a/insalan/tournament/admin.py b/insalan/tournament/admin.py index efd12f30..36d7ee13 100644 --- a/insalan/tournament/admin.py +++ b/insalan/tournament/admin.py @@ -407,28 +407,32 @@ def __init__(self, *args, **kwargs): "content_type" ) + seat_slot = self.fields.get("seat_slot") + if (seat_slot and self.instance.tournament): + seat_slot.queryset = seat_slot.queryset.filter( + tournament=self.instance.tournament + ).filter( + team=None + ) + def clean(self): """ validate seat slot """ seat_slot = self.cleaned_data.get("seat_slot") - tournament = self.cleaned_data.get("tournament") - team_id = self.instance.id + tournament = self.cleaned_data.get("tournament") or self.instance.tournament - if seat_slot.tournament.id != tournament.id: - raise ValidationError( - _("Ce slot appartient à un autre tournoi.") - ) + if seat_slot is not None: + # filters mean if it's not the same tournament, seat_slot is None => impossible + if seat_slot.tournament.id != tournament.id: + raise ValidationError(_("Ce slot appartient à un autre tournoi.")) - if hasattr(seat_slot, "team") and seat_slot.team.id != team_id: - raise ValidationError( - _("Slot déjà utilisé.") - ) + # filters mean if it's used, seat_slot is None => impossible + if hasattr(seat_slot, "team") and seat_slot.team.id != self.instance.id: + raise ValidationError(_("Slot déjà utilisé.")) - if seat_slot.seats.count() != tournament.game.players_per_team: - raise ValidationError( - _("Slot inadapté au tournoi.") - ) + if seat_slot.seats.count() != tournament.game.players_per_team: + raise ValidationError(_("Slot inadapté au tournoi.")) return self.cleaned_data diff --git a/insalan/tournament/test/test_seat_forms.py b/insalan/tournament/test/test_seat_forms.py index 80ec46c4..453c66b7 100644 --- a/insalan/tournament/test/test_seat_forms.py +++ b/insalan/tournament/test/test_seat_forms.py @@ -1,15 +1,17 @@ import json +from django.forms import ValidationError from django.test import TestCase from insalan.tournament.models import ( Event, Tournament, Game, + Team, Seat, SeatSlot, ) -from insalan.tournament.admin import EventForm, TournamentForm, GameForm +from insalan.tournament.admin import EventForm, TournamentForm, GameForm, TeamForm class SeatsFieldTestCase(TestCase): @@ -55,6 +57,8 @@ def setUp(self) -> None: for _ in range(len(seats2[:: self.game_two.players_per_team])) ] + self.team = Team.objects.create(tournament=self.tournament, name="Test Team") + seats1_groups = [ seats1[i : i + self.game_one.players_per_team] for i in range(0, len(seats1), self.game_one.players_per_team) @@ -317,3 +321,66 @@ def test_game_form_resets_slots_if_players_per_team_changed(self): form.clean() self.assertFalse(SeatSlot.objects.filter(tournament=self.tournament).exists()) + + def test_team_form_sets_seat_slot(self): + self.assertIsNone(self.team.seat_slot) + + form = TeamForm( + instance=self.team, + data={"seat_slot": self.slots1[0].id}, + ) + form.full_clean() + form.clean() + + self.assertEqual(self.team.seat_slot.id, self.slots1[0].id) + + def test_team_form_ignores_seat_slot_if_wrong_tournament(self): + self.assertIsNone(self.team.seat_slot) + + form = TeamForm( + instance=self.team, + data={"seat_slot": self.slots2[0].id}, + ) + form.full_clean() + form.clean() + + # here, the slot object is not found because the query set for that + # field is filtered for that specific tournament. it seems the passed + # value is silently discarded + self.assertIsNone(self.team.seat_slot) + + def test_team_form_ignores_seat_slot_if_slot_taken(self): + self.assertIsNone(self.team.seat_slot) + + slot = SeatSlot.objects.create(tournament=self.tournament) + slot.seats.set(self.slots1[0].seats.all()) + + team2 = Team.objects.create( + tournament=self.tournament, name="Test Team 2", seat_slot=slot + ) + team2.save() + + form = TeamForm( + instance=self.team, + data={"seat_slot": slot.id}, + ) + form.full_clean() + form.clean() + + # here, the slot object is not found because the query set for that + # field is filtered to include only unused slots. it seems the passed + # value is silently discarded + self.assertIsNone(self.team.seat_slot) + + def test_team_form_invalid_if_wrong_nb_seats_in_slot(self): + self.assertIsNone(self.team.seat_slot) + + slot = SeatSlot.objects.create(tournament=self.tournament) + slot.seats.set(self.slots1[0].seats.all()[:4]) + + form = TeamForm( + instance=self.team, + data={"seat_slot": slot.id}, + ) + + self.assertFalse(form.is_valid())