fix(gameplay): gate next-round replay on prior scoreboard exit
This commit is contained in:
@@ -1399,10 +1399,19 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
mock_sync_broadcast_phase_event.assert_called_once()
|
mock_sync_broadcast_phase_event.assert_called_once()
|
||||||
self.assertEqual(mock_sync_broadcast_phase_event.call_args.args[1], "phase.lie_started")
|
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")
|
self.client.login(username="host_reveal", password="secret123")
|
||||||
|
ScoreEvent.objects.filter(session=self.session).delete()
|
||||||
self.session.status = GameSession.Status.LIE
|
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(
|
response = self.client.post(
|
||||||
reverse(
|
reverse(
|
||||||
@@ -1416,9 +1425,11 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
self.assertEqual(response.json()["error_code"], "next_round_invalid_phase")
|
self.assertEqual(response.json()["error_code"], "next_round_invalid_phase")
|
||||||
self.session.refresh_from_db()
|
self.session.refresh_from_db()
|
||||||
self.assertEqual(self.session.status, GameSession.Status.LIE)
|
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=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=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):
|
def test_start_next_round_clears_existing_next_round_bootstrap_state(self):
|
||||||
self.client.login(username="host_reveal", password="secret123")
|
self.client.login(username="host_reveal", password="secret123")
|
||||||
|
|||||||
@@ -1135,6 +1135,25 @@ def start_next_round(request: HttpRequest, code: str) -> JsonResponse:
|
|||||||
if locked_session.current_round <= 1:
|
if locked_session.current_round <= 1:
|
||||||
return api_error(request, code="next_round_invalid_phase", status=400)
|
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(
|
next_round_config = RoundConfig.objects.filter(
|
||||||
session=locked_session,
|
session=locked_session,
|
||||||
number=locked_session.current_round,
|
number=locked_session.current_round,
|
||||||
|
|||||||
Reference in New Issue
Block a user