From 0a135c2149c40ccd3fbf2d1abe0b29d330b969fa Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Mon, 13 Apr 2026 13:00:16 -0400 Subject: [PATCH] implemented sig_confirm view: guards (403 unseated, 400 wrong phase, 400 not-all-ready), significator assignment from reservations, polarity_room_done + pick_sky_available broadcasts, SKY_SELECT advance when both polarities done Co-Authored-By: Claude Sonnet 4.6 --- src/apps/epic/views.py | 43 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/apps/epic/views.py b/src/apps/epic/views.py index 17e80e6..2c1ba63 100644 --- a/src/apps/epic/views.py +++ b/src/apps/epic/views.py @@ -803,7 +803,48 @@ def sig_ready(request, room_id): @login_required def sig_confirm(request, room_id): - """No-op: polarity confirmation is now driven server-side by threading.Timer in tasks.py.""" + """Finalise polarity group once the countdown fires. + POST body: polarity=levity|gravity + """ + if request.method != "POST": + return HttpResponse(status=405) + room = Room.objects.get(id=room_id) + if room.table_status != Room.SIG_SELECT: + return HttpResponse(status=400) + user_seat = _canonical_user_seat(room, request.user) + if user_seat is None: + return HttpResponse(status=403) + + polarity = request.POST.get("polarity", SigReservation.LEVITY) + polarity_roles = _LEVITY_ROLES if polarity == SigReservation.LEVITY else _GRAVITY_ROLES + + # Idempotency: seats already have significators + if not room.table_seats.filter(role__in=polarity_roles, significator__isnull=True).exists(): + return HttpResponse(status=200) + + # All three in the polarity group must be ready + ready_count = SigReservation.objects.filter(room=room, polarity=polarity, ready=True).count() + if ready_count < 3: + return HttpResponse(status=400) + + # Assign significators from reservations + reservations = list( + SigReservation.objects.filter(room=room, polarity=polarity, ready=True) + .select_related('seat', 'card') + ) + for res in reservations: + if res.seat: + res.seat.significator = res.card + res.seat.save(update_fields=['significator']) + SigReservation.objects.filter(room=room, polarity=polarity).update(countdown_remaining=None) + + _notify_polarity_room_done(room_id, polarity) + + # If both polarities are now done, advance to SKY_SELECT + if not room.table_seats.filter(significator__isnull=True).exists(): + Room.objects.filter(id=room_id).update(table_status=Room.SKY_SELECT) + _notify_pick_sky_available(room_id) + return HttpResponse(status=200)