fix(gameplay): gate next-round replay on scoreboard exit marker
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.2 on 2026-03-17 08:24
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('fupogfakta', '0006_merge_20260315_1249'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='roundconfig',
|
||||||
|
name='started_from_scoreboard',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -83,6 +83,7 @@ class RoundConfig(models.Model):
|
|||||||
points_bluff = models.IntegerField(default=2)
|
points_bluff = models.IntegerField(default=2)
|
||||||
lie_seconds = models.PositiveIntegerField(default=45)
|
lie_seconds = models.PositiveIntegerField(default=45)
|
||||||
guess_seconds = models.PositiveIntegerField(default=30)
|
guess_seconds = models.PositiveIntegerField(default=30)
|
||||||
|
started_from_scoreboard = models.BooleanField(default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (("session", "number"),)
|
unique_together = (("session", "number"),)
|
||||||
|
|||||||
@@ -1377,7 +1377,12 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
self.assertEqual(self.session.status, GameSession.Status.LIE)
|
self.assertEqual(self.session.status, GameSession.Status.LIE)
|
||||||
self.assertEqual(self.session.current_round, 2)
|
self.assertEqual(self.session.current_round, 2)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
RoundConfig.objects.filter(session=self.session, number=2, category=self.category).exists()
|
RoundConfig.objects.filter(
|
||||||
|
session=self.session,
|
||||||
|
number=2,
|
||||||
|
category=self.category,
|
||||||
|
started_from_scoreboard=True,
|
||||||
|
).exists()
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
RoundQuestion.objects.filter(session=self.session, round_number=2, question=self.next_question).exists()
|
RoundQuestion.objects.filter(session=self.session, round_number=2, question=self.next_question).exists()
|
||||||
@@ -1415,7 +1420,7 @@ class RevealRoundFlowTests(TestCase):
|
|||||||
self.session.status = GameSession.Status.LIE
|
self.session.status = GameSession.Status.LIE
|
||||||
self.session.current_round = 2
|
self.session.current_round = 2
|
||||||
self.session.save(update_fields=["status", "current_round"])
|
self.session.save(update_fields=["status", "current_round"])
|
||||||
RoundConfig.objects.create(session=self.session, number=2, category=self.category)
|
RoundConfig.objects.create(session=self.session, number=2, category=self.category, started_from_scoreboard=False)
|
||||||
RoundQuestion.objects.create(
|
RoundQuestion.objects.create(
|
||||||
session=self.session,
|
session=self.session,
|
||||||
round_number=2,
|
round_number=2,
|
||||||
|
|||||||
@@ -1001,6 +1001,7 @@ def start_next_round(request: HttpRequest, code: str) -> JsonResponse:
|
|||||||
guess_seconds=previous_round_config.guess_seconds,
|
guess_seconds=previous_round_config.guess_seconds,
|
||||||
points_correct=previous_round_config.points_correct,
|
points_correct=previous_round_config.points_correct,
|
||||||
points_bluff=previous_round_config.points_bluff,
|
points_bluff=previous_round_config.points_bluff,
|
||||||
|
started_from_scoreboard=True,
|
||||||
)
|
)
|
||||||
locked_session.current_round = next_round_number
|
locked_session.current_round = next_round_number
|
||||||
|
|
||||||
@@ -1019,31 +1020,16 @@ 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,
|
||||||
).select_related("category").first()
|
).select_related("category").first()
|
||||||
round_question = _get_current_round_question(locked_session)
|
round_question = _get_current_round_question(locked_session)
|
||||||
if next_round_config is None or round_question is None:
|
if (
|
||||||
|
next_round_config is None
|
||||||
|
or not next_round_config.started_from_scoreboard
|
||||||
|
or round_question is None
|
||||||
|
):
|
||||||
return api_error(request, code="next_round_invalid_phase", status=400)
|
return api_error(request, code="next_round_invalid_phase", status=400)
|
||||||
else:
|
else:
|
||||||
return api_error(request, code="next_round_invalid_phase", status=400)
|
return api_error(request, code="next_round_invalid_phase", status=400)
|
||||||
|
|||||||
Reference in New Issue
Block a user