diff --git a/lobby/tests.py b/lobby/tests.py index 6722cf5..5ee08e1 100644 --- a/lobby/tests.py +++ b/lobby/tests.py @@ -1399,10 +1399,19 @@ class RevealRoundFlowTests(TestCase): mock_sync_broadcast_phase_event.assert_called_once() self.assertEqual(mock_sync_broadcast_phase_event.call_args.args[1], "phase.lie_started") - def test_start_next_round_rejects_plain_first_round_lie_phase(self): + def test_start_next_round_rejects_plain_lie_phase_without_prior_scoreboard_transition(self): self.client.login(username="host_reveal", password="secret123") + ScoreEvent.objects.filter(session=self.session).delete() self.session.status = GameSession.Status.LIE - self.session.save(update_fields=["status"]) + self.session.current_round = 2 + self.session.save(update_fields=["status", "current_round"]) + RoundConfig.objects.create(session=self.session, number=2, category=self.category) + RoundQuestion.objects.create( + session=self.session, + round_number=2, + question=self.next_question, + correct_answer=self.next_question.correct_answer, + ) response = self.client.post( reverse( @@ -1416,9 +1425,11 @@ class RevealRoundFlowTests(TestCase): self.assertEqual(response.json()["error_code"], "next_round_invalid_phase") self.session.refresh_from_db() self.assertEqual(self.session.status, GameSession.Status.LIE) - self.assertEqual(self.session.current_round, 1) + self.assertEqual(self.session.current_round, 2) self.assertEqual(RoundConfig.objects.filter(session=self.session, number=1).count(), 1) + self.assertEqual(RoundConfig.objects.filter(session=self.session, number=2).count(), 1) self.assertEqual(RoundQuestion.objects.filter(session=self.session, round_number=1).count(), 1) + self.assertEqual(RoundQuestion.objects.filter(session=self.session, round_number=2).count(), 1) def test_start_next_round_clears_existing_next_round_bootstrap_state(self): self.client.login(username="host_reveal", password="secret123") diff --git a/lobby/views.py b/lobby/views.py index 64aa0b0..222fe1e 100644 --- a/lobby/views.py +++ b/lobby/views.py @@ -1135,6 +1135,25 @@ def start_next_round(request: HttpRequest, code: str) -> JsonResponse: if locked_session.current_round <= 1: return api_error(request, code="next_round_invalid_phase", status=400) + previous_round_question = RoundQuestion.objects.filter( + session=locked_session, + round_number=locked_session.current_round - 1, + ).first() + if previous_round_question is None: + return api_error(request, code="next_round_invalid_phase", status=400) + + previous_round_players_count = Player.objects.filter(session=locked_session).count() + previous_round_guess_count = Guess.objects.filter(round_question=previous_round_question).count() + previous_round_has_score_events = ScoreEvent.objects.filter( + session=locked_session, + meta__round_question_id=previous_round_question.id, + ).exists() + previous_round_reveal_resolved = previous_round_has_score_events or ( + previous_round_players_count > 0 and previous_round_guess_count >= previous_round_players_count + ) + if not previous_round_reveal_resolved: + return api_error(request, code="next_round_invalid_phase", status=400) + next_round_config = RoundConfig.objects.filter( session=locked_session, number=locked_session.current_round,