thorn.django.models — Thorn 1.3.0 documentation

# Source code for thorn.django.models

    """

        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
    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')

        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),
            )