Source code for thorn.django.models

"""Django models required to dispatch webhook events."""
from __future__ import absolute_import, unicode_literals

from uuid import uuid4

from django.conf import settings as django_settings
from django.db import models
from django.utils import text
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

from thorn.conf import event_choices, MIME_JSON, MIME_URLFORM
from thorn.generic.models import AbstractSubscriber, SubscriberModelMixin
from thorn.utils.hmac import random_secret

from .managers import SubscriberManager

__all__ = ['Subscriber']

#: max size when indexing InnoDB utf8mb4
#: reportedly this is caused by MySQL being purposefully and irreversibly
#: brain-damaged: https://code.djangoproject.com/ticket/18392
CHAR_MAX_LENGTH = 190

CONTENT_TYPES = {
    MIME_JSON,
    MIME_URLFORM,
}


# Django migrations cannot handle partial objects, ugh...
def random_secret64():
    return random_secret(64)


@AbstractSubscriber.register
@python_2_unicode_compatible
[docs]class Subscriber(models.Model, SubscriberModelMixin): objects = SubscriberManager() uuid = models.UUIDField( _('UUID'), default=uuid4, editable=False, unique=True, null=False, help_text=_('Unique identifier for this subscriber.') ) event = models.CharField( _('event'), max_length=CHAR_MAX_LENGTH, choices=event_choices(), db_index=True, help_text=_('Name of event to connect with'), ) url = models.URLField( _('URL'), max_length=CHAR_MAX_LENGTH, db_index=True, help_text=_('Callback URL'), ) user = models.ForeignKey( django_settings.AUTH_USER_MODEL, related_name='%(app_label)s_%(class)s', null=True, ) hmac_secret = models.TextField( _('HMAC Secret'), default=random_secret64, help_text=_('Specify HMAC secret for endpoints to verify'), ) hmac_digest = models.CharField( _('HMAC Digest Type'), max_length=64, choices=[ ('SHA512', 'sha512'), ('SHA256', 'sha256'), ('SHA1', 'sha1'), ], default='sha256', help_text=_('Specify HMAC digest type (use sha256 if uncertain)'), ) content_type = models.CharField( _('content type'), max_length=CHAR_MAX_LENGTH, choices=zip(CONTENT_TYPES, CONTENT_TYPES), default=MIME_JSON, help_text='Desired content type for requests to this callback.' ) created_at = models.DateTimeField( _('created at'), editable=False, auto_now_add=True) updated_at = models.DateTimeField( _('updated_at'), editable=False, auto_now=True, ) class Meta: verbose_name = _('subscriber') verbose_name_plural = _('subscriber') # ordering by hostname for ability to optimize for keepalive. ordering = ['url', '-created_at'] get_latest_by = 'updated_at' unique_together = ('url', 'event')
[docs] def user_ident(self): return self.user and self.user.pk
def __str__(self): return '{0} -> {1}'.format( self.event, text.Truncator(self.url).chars(43), )