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