Files @ 249adba527d9
Branch filter:

Location: symposion_app/pinaxcon/raffle/signals.py

Joel Addison
Improve schedule - speaker nav

Add link to speaker profile from presentation detail page.
Include twitter and homepage on speaker profile.
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.")