Source code for boardinghouse.contrib.invite.models

import datetime
import uuid

from django.conf import settings
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now

# Can't import into the class namespace: we need to do it at the module.

from boardinghouse.base import SharedSchemaModel

INVITATION_EXPIRY = getattr(settings, 'INVITATION_EXPIRY', datetime.timedelta(7))


class InvitationQuerySet(models.query.QuerySet):
    def not_handled(self):
        return self.filter(declined_at=None).filter(accepted_at=None)

    def pending(self):
        return self.not_handled().filter(
            created_at__gte=now() - INVITATION_EXPIRY
        )

    def not_pending(self):
        # Any invitations that have expired, have been accepted or declined.
        return self.exclude(pk__in=self.pending())

    def expired(self):
        return self.not_handled().filter(
            created_at__lt=now() - INVITATION_EXPIRY
        )

    def accepted(self):
        return self.exclude(accepted_at=None)

    def declined(self):
        return self.exclude(declined_at=None)

    def for_email(self, email):
        return self.filter(email=email)


[docs]class Invitation(SharedSchemaModel): email = models.EmailField(verbose_name=_('Email address')) sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='sent_invitations') message = models.TextField() schema = models.ForeignKey(settings.BOARDINGHOUSE_SCHEMA_MODEL, related_name='invitations') redemption_code = models.UUIDField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) # Can we ensure that at most one of these two is not null? accepted_at = models.DateTimeField(null=True, blank=True) declined_at = models.DateTimeField(null=True, blank=True) accepted_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='accepted_invitations', null=True, blank=True) objects = InvitationQuerySet.as_manager() class Meta: ordering = ('created_at',) app_label = 'invite' def __unicode__(self): return '[%s] Invitation to %s from %s to join %s' % ( unicode(self.status), self.email, self.sender, self.schema.name ) def save(self, *args, **kwargs): if not self.redeemed and not self.redemption_code: self.redemption_code = uuid.uuid4() return super(Invitation, self).save(*args, **kwargs) @property def redeemed(self): return self.accepted_at or self.declined_at @property def declined(self): return self.declined_at is not None @property def accepted(self): return self.accepted_at is not None @property def expired(self): return self.created_at < now() - INVITATION_EXPIRY @property def redeemable(self): return not (self.expired or self.redeemed) @property def status(self): if self.declined: return _('DECLINED') if self.accepted: return _('ACCEPTED') if self.expired: return _('EXPIRED') return _('PENDING') @property def expiry_date(self): return self.created_at + INVITATION_EXPIRY