Example #1
0
class Body(models.Model):
    """Body model

    Object manager has a get_or_create() method that deals with duplicated
    bodies.

    This model expects and returns binary data, converting to and from str happens elsewhere
    """
    hashed = models.CharField(max_length=80, unique=True,
                              validators=[validators.ProhibitNullCharactersValidator()])  # <algo>:<hash>
    data = models.BinaryField(default=b"")

    objects = BodyQuerySet.as_manager()

    def __str__(self):
        return self.hashed
Example #2
0
    def clean_username(self):
        username = self.cleaned_data["username"]

        valids = [validators.ProhibitNullCharactersValidator()]
        if six.PY3:
            valids.append(UnicodeUsernameValidator())
        else:
            valids.append(ASCIIUsernameValidator())

        for validator in valids:
            validator(username)

        if get_user_model().objects.filter(username__iexact=username).exists():
            raise exceptions.ValidationError(_("A user with that username already exists."), code='duplicate_username')

        return username
Example #3
0
class Domain(models.Model):
    """Domain model

    `owner` is the user who controls the domain
    """
    domain = models.CharField(
        max_length=253,
        unique=True,
        validators=[validators.ProhibitNullCharactersValidator()])
    enabled = models.BooleanField(default=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              null=True,
                              blank=True,
                              default=None,
                              on_delete=models.PROTECT)

    objects = DomainQuerySet.as_manager()

    def __str__(self):
        return self.domain
Example #4
0
class Request(models.Model):
    """Inbox allocation request model"""
    amount = models.IntegerField(help_text=_("Pool increase requested"))
    succeeded = models.NullBooleanField(
        "accepted",
        default=None,
        help_text=_("has the request been accepted?"))
    date = models.DateTimeField("requested",
                                auto_now_add=True,
                                db_index=True,
                                help_text=_("date requested"))
    date_decided = models.DateTimeField(
        null=True, help_text=_("date staff accepted/rejected request"))
    authorizer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name="request_authorizer",
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        help_text=_("who accepted (or rejected) this request?"))
    requester = models.ForeignKey(settings.AUTH_USER_MODEL,
                                  related_name="requester")
    result = models.CharField(
        "comment",
        max_length=1024,
        blank=True,
        null=True,
        validators=[validators.ProhibitNullCharactersValidator()])

    def save(self, *args, **kwargs):
        if self.succeeded:
            self.requester.inboxenprofile.pool_amount = models.F(
                "pool_amount") + self.amount
            self.requester.inboxenprofile.save(update_fields=["pool_amount"])
        super(Request, self).save(*args, **kwargs)

    def __str__(self):
        return u"Request for %s (%s)" % (self.requester, self.succeeded)
Example #5
0
class HelpBasePage(HelpAbstractPage):
    # Much of this class is taken from Wagtail 1.12.1
    #
    # Copyright (c) 2014 Torchbox Ltd and individual contributors.
    # All rights reserved.
    #
    # Redistribution and use in source and binary forms, with or without modification,
    # are permitted provided that the following conditions are met:
    #
    #     1. Redistributions of source code must retain the above copyright notice,
    #        this list of conditions and the following disclaimer.
    #
    #     2. Redistributions in binary form must reproduce the above copyright
    #        notice, this list of conditions and the following disclaimer in the
    #        documentation and/or other materials provided with the distribution.
    #
    #     3. Neither the name of Torchbox nor the names of its contributors may be used
    #        to endorse or promote products derived from this software without
    #        specific prior written permission.
    #
    # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    parent = TreeForeignKey('self',
                            null=True,
                            blank=True,
                            related_name='children',
                            on_delete=models.CASCADE)
    title = models.CharField(
        max_length=255,
        validators=[validators.ProhibitNullCharactersValidator()])
    description = models.TextField(
        blank=True, validators=[validators.ProhibitNullCharactersValidator()])

    live = models.BooleanField(default=False)
    in_menu = models.BooleanField(default=False)
    content_type = models.ForeignKey(
        'contenttypes.ContentType',
        related_name='cms_pages',
        on_delete=models.PROTECT,
    )
    slug = models.SlugField(
        max_length=255,
        validators=[validators.ProhibitNullCharactersValidator()])
    url_cache = models.CharField(
        max_length=255,
        default="",
        validators=[validators.ProhibitNullCharactersValidator()])

    template = "cms/help_base.html"

    admin_fields = ("title", "description", "slug", "live", "in_menu")

    # None means anything is allowed, set to [] if you want to
    # disallow this model from having any parent or children
    allowed_parents = None
    allowed_children = None

    @cached_property
    def url(self):
        # generate_url doesn't cache the url to url_cache (because we don't
        # know if we're going to save), so this property is a *cached* property
        # so we never call generate_url twice
        if self.url_cache:
            return self.url_cache
        else:
            return self.generate_url()

    def generate_url(self):
        if self.parent:
            return self.parent.url + self.slug + "/"
        else:
            return settings.CMS_ROOT_URL

    @cached_property
    def specific(self):
        """
        Return this page in its most specific subclassed form.
        """
        # the ContentType.objects manager keeps a cache, so this should potentially
        # avoid a database lookup over doing self.content_type. I think.
        content_type = ContentType.objects.get_for_id(self.content_type_id)
        model_class = content_type.model_class()
        if model_class is None:
            # Cannot locate a model class for this content type. This might happen
            # if the codebase and database are out of sync (e.g. the model exists
            # on a different git branch and we haven't rolled back migrations before
            # switching branches); if so, the best we can do is return the page
            # unchanged.
            return self
        elif isinstance(self, model_class):
            # self is already the an instance of the most specific class
            return self
        else:
            return content_type.get_object_for_this_type(id=self.id)

    @cached_property
    def specific_class(self):
        """
        Return the class that this page would be if instantiated in its
        most specific form
        """
        content_type = ContentType.objects.get_for_id(self.content_type_id)
        return content_type.model_class()

    def route(self, request, path_components):
        if path_components:
            # request is for a child of this page
            child_slug = path_components[0]
            remaining_components = path_components[1:]

            try:
                subpage = self.get_children().get(slug=child_slug)
            except HelpBasePage.DoesNotExist:
                raise Http404

            return subpage.specific.route(request, remaining_components)

        else:
            # request is for this very page
            if self.live:
                return (self, [], {})
            else:
                raise Http404

    def serve(self, request, *args, **kwargs):
        assert type(
            self
        ) != HelpBasePage, "serve method was called directly on a HelpBasePage object"

        return TemplateResponse(request, self.template,
                                self.get_context(request, *args, **kwargs))

    def get_context(self, request, *args, **kwargs):
        return {
            "page": self,
        }

    def save(self, *args, **kwargs):
        self.url_cache = self.generate_url()
        return super(HelpBasePage, self).save(*args, **kwargs)

    class Meta:
        manager_inheritance_from_future = True
        unique_together = ("slug", "parent")
Example #6
0
class Inbox(models.Model):
    """Inbox model

    Object manager has a custom create() method to generate a random local part
    and a from_string() method to grab an Inbox object from the database given
    a string "inbox@domain"

    `flags` are "deleted" and "new".
    * "deleted" is obvious (and should be used instead of deleting the model)
    * "new" should be set when an email is added to the inbox and unset when
      the inbox is viewed
    * "disabled" is a bit like "deleted", but incoming mail will be deffered, not rejected
    """
    inbox = models.CharField(
        max_length=64,
        validators=[validators.ProhibitNullCharactersValidator()])
    domain = models.ForeignKey(Domain, on_delete=models.PROTECT)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             null=True,
                             on_delete=models.SET_NULL)
    created = models.DateTimeField('Created')
    flags = BitField(flags=("deleted", "new", "exclude_from_unified",
                            "disabled", "pinned"),
                     default=0)
    description = models.CharField(
        max_length=256,
        null=True,
        blank=True,
        validators=[validators.ProhibitNullCharactersValidator()])

    deleted = models.BooleanField(default=False)
    new = models.BooleanField(default=False)
    exclude_from_unified = models.BooleanField(
        default=False, verbose_name=_("Exclude from Unified Inbox"))
    disabled = models.BooleanField(
        default=False,
        verbose_name=_("Disable Inbox"),
        help_text=_("This Inbox will no longer receive emails."))
    pinned = models.BooleanField(default=False,
                                 verbose_name=_("Pin Inbox to top"))

    objects = InboxQuerySet.as_manager()

    _bool_label_order = ["new", "disabled", "pinned"]

    def get_bools_for_labels(self):
        for key in self._bool_label_order:
            yield (key, getattr(self, key))

    def __str__(self):
        return u"%s@%s" % (self.inbox, self.domain.domain)

    def __repr__(self):
        u_rep = six.text_type(self)
        if self.deleted:
            u_rep = "%s (deleted)" % u_rep
        return smart_str(u'<%s: %s>' % (self.__class__.__name__, u_rep),
                         errors="replace")

    class Meta:
        verbose_name_plural = "Inboxes"
        unique_together = (('inbox', 'domain'), )