Files
@ 7fac10241ec7
Branch filter:
Location: symposion_app/pinaxcon/raffle/signals.py - annotation
7fac10241ec7
2.8 KiB
text/x-python
Improve attendee reports
Display attendee profile data in normal table without DataTables so
sorting is not applied, causing data to be confusing to read.
Include item quantity in attendee data report for accurate schwag packing.
Display attendee profile data in normal table without DataTables so
sorting is not applied, causing data to be confusing to read.
Include item quantity in attendee data report for accurate schwag packing.
d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c 970ec9184c57 970ec9184c57 970ec9184c57 d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c d1ff8d72533c | from itertools import chain
from random import sample
from django.db import IntegrityError
from django.db.models.signals import post_save, pre_save, pre_delete, post_init
from django.dispatch import receiver
from pinaxcon.raffle.models import DrawnTicket, Raffle, Draw, Prize
# Much of the following could be handled by directly overriding the
# relevant model methods. However, since `.objects.delete()` bypasses
# a model's delete() method but not its pre_ and post_delete signals,
# using signals gives us slightly better coverage of edge cases.
#
# In order to avoid mixing the two approaches we make extensive use of
# signals.
@receiver(post_save, sender=Draw)
def draw_raffle_tickets(sender, instance, created, **kwargs):
"""
Draws tickets once a :model:`pinaxcon_raffle.Draw` instance
has been created and prizes are still available.
"""
if not created:
return
raffle = instance.raffle
prizes = raffle.prizes.filter(winning_ticket__isnull=True)
tickets = list(chain(*(ticket[1] for ticket in raffle.get_tickets())))
if not tickets:
return
drawn_tickets = sample(tickets, len(prizes))
for prize, ticket in zip(prizes, drawn_tickets):
item_id = int(ticket.split('-')[0])
drawn_ticket = DrawnTicket.objects.create(
draw=instance,
prize=prize,
ticket=ticket,
lineitem_id=item_id,
)
prize.winning_ticket = drawn_ticket
prize.save(update_fields=('winning_ticket',))
@receiver(post_init, sender=Prize)
def set_prize_lock(sender, instance, **kwargs):
"""Locks :model:`pinaxcon_raffle.Prize` if a winner exists."""
instance._locked = instance.winning_ticket is not None
@receiver(pre_save, sender=Prize)
def enforce_prize_lock(sender, instance, **kwargs):
"""Denies updates to :model:`pinaxcon_raffle.Prize` if lock is in place."""
if instance.locked:
raise IntegrityError("Updating a locked prize is not allowed.")
@receiver(pre_delete, sender=Prize)
def prevent_locked_prize_deletion(sender, instance, **kwargs):
"""Denies deletion of :model:`pinaxcon_raffle.Prize` if lock is in place."""
if instance.locked:
raise IntegrityError("Deleting a locked prize is not allowed.")
@receiver(pre_delete, sender=DrawnTicket)
def prevent_drawn_ticket_deletion(sender, instance, **kwargs):
"""Protects :model:`pinaxcon_raffle.DrawnTicket` from deletion if lock is in place."""
if instance.locked:
raise IntegrityError("Deleting a drawn ticket is not allowed.")
@receiver(pre_save, sender=DrawnTicket)
def prevent_drawn_ticket_update(sender, instance, **kwargs):
"""Protects :model:`pinaxcon_raffle.DrawnTicket` from updates."""
if getattr(instance, 'pk', None):
raise IntegrityError("Updating a drawn ticket is not allowed.")
|